mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
a1b4554cdb
Changed the min OS version to iOS 13.0 (support for 'Identifiable') Removed the alternate approaches to fetching the userKeyPair and userPublicKeyHexString (no consistently routed through the caching method) Migrated the 'OWSIdentityManager' logic to use the new 'Identity' type Added the 'Setting' table and got the pattern working fairly nicely (unfortunately there isn't a good way to avoid key collision without proper enums) Updated the SessionSnodeKit to migration it's data from YDB to GRDB Updated the SessionSnodeKit to use GRDB throughout it's logic
207 lines
11 KiB
Swift
207 lines
11 KiB
Swift
import Sodium
|
|
|
|
final class RegisterVC : BaseVC {
|
|
private var seed: Data! { didSet { updateKeyPair() } }
|
|
private var ed25519KeyPair: Sign.KeyPair!
|
|
private var x25519KeyPair: ECKeyPair! { didSet { updatePublicKeyLabel() } }
|
|
|
|
// MARK: Components
|
|
private lazy var publicKeyLabel: UILabel = {
|
|
let result = UILabel()
|
|
result.textColor = Colors.text
|
|
result.font = Fonts.spaceMono(ofSize: isIPhone5OrSmaller ? Values.mediumFontSize : 20)
|
|
result.numberOfLines = 0
|
|
result.lineBreakMode = .byCharWrapping
|
|
result.accessibilityLabel = "Session ID label"
|
|
return result
|
|
}()
|
|
|
|
private lazy var copyPublicKeyButton: Button = {
|
|
let result = Button(style: .prominentOutline, size: .large)
|
|
result.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal)
|
|
result.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize)
|
|
result.addTarget(self, action: #selector(copyPublicKey), for: UIControl.Event.touchUpInside)
|
|
return result
|
|
}()
|
|
|
|
private lazy var legalLabel: UILabel = {
|
|
let result = UILabel()
|
|
result.textColor = Colors.text
|
|
result.font = .systemFont(ofSize: Values.verySmallFontSize)
|
|
let text = "By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy"
|
|
let attributedText = NSMutableAttributedString(string: text, attributes: [ .font : UIFont.systemFont(ofSize: Values.verySmallFontSize) ])
|
|
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service"))
|
|
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)"))
|
|
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy"))
|
|
result.attributedText = attributedText
|
|
result.numberOfLines = 0
|
|
result.textAlignment = .center
|
|
result.lineBreakMode = .byWordWrapping
|
|
return result
|
|
}()
|
|
|
|
// MARK: Lifecycle
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
setUpGradientBackground()
|
|
setUpNavBarStyle()
|
|
setUpNavBarSessionIcon()
|
|
// Set up title label
|
|
let titleLabel = UILabel()
|
|
titleLabel.textColor = Colors.text
|
|
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
|
|
titleLabel.text = NSLocalizedString("vc_register_title", comment: "")
|
|
titleLabel.numberOfLines = 0
|
|
titleLabel.lineBreakMode = .byWordWrapping
|
|
// Set up explanation label
|
|
let explanationLabel = UILabel()
|
|
explanationLabel.textColor = Colors.text
|
|
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
|
|
explanationLabel.text = NSLocalizedString("vc_register_explanation", comment: "")
|
|
explanationLabel.numberOfLines = 0
|
|
explanationLabel.lineBreakMode = .byWordWrapping
|
|
// Set up public key label container
|
|
let publicKeyLabelContainer = UIView()
|
|
publicKeyLabelContainer.addSubview(publicKeyLabel)
|
|
publicKeyLabel.pin(to: publicKeyLabelContainer, withInset: Values.mediumSpacing)
|
|
publicKeyLabelContainer.layer.cornerRadius = TextField.cornerRadius
|
|
publicKeyLabelContainer.layer.borderWidth = 1
|
|
publicKeyLabelContainer.layer.borderColor = Colors.text.cgColor
|
|
// Set up spacers
|
|
let topSpacer = UIView.vStretchingSpacer()
|
|
let bottomSpacer = UIView.vStretchingSpacer()
|
|
// Set up register button
|
|
let registerButton = Button(style: .prominentFilled, size: .large)
|
|
registerButton.setTitle(NSLocalizedString("continue_2", comment: ""), for: UIControl.State.normal)
|
|
registerButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize)
|
|
registerButton.addTarget(self, action: #selector(register), for: UIControl.Event.touchUpInside)
|
|
// Set up button stack view
|
|
let buttonStackView = UIStackView(arrangedSubviews: [ registerButton, copyPublicKeyButton ])
|
|
buttonStackView.axis = .vertical
|
|
buttonStackView.spacing = isIPhone5OrSmaller ? Values.smallSpacing : Values.mediumSpacing
|
|
buttonStackView.alignment = .fill
|
|
// Set up button stack view container
|
|
let buttonStackViewContainer = UIView()
|
|
buttonStackViewContainer.addSubview(buttonStackView)
|
|
buttonStackView.pin(.leading, to: .leading, of: buttonStackViewContainer, withInset: Values.massiveSpacing)
|
|
buttonStackView.pin(.top, to: .top, of: buttonStackViewContainer)
|
|
buttonStackViewContainer.pin(.trailing, to: .trailing, of: buttonStackView, withInset: Values.massiveSpacing)
|
|
buttonStackViewContainer.pin(.bottom, to: .bottom, of: buttonStackView)
|
|
// Set up legal label
|
|
legalLabel.isUserInteractionEnabled = true
|
|
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleLegalLabelTapped))
|
|
legalLabel.addGestureRecognizer(tapGestureRecognizer)
|
|
// Set up legal label container
|
|
let legalLabelContainer = UIView()
|
|
legalLabelContainer.set(.height, to: Values.onboardingButtonBottomOffset)
|
|
legalLabelContainer.addSubview(legalLabel)
|
|
legalLabel.pin(.leading, to: .leading, of: legalLabelContainer, withInset: Values.massiveSpacing)
|
|
legalLabel.pin(.top, to: .top, of: legalLabelContainer)
|
|
legalLabelContainer.pin(.trailing, to: .trailing, of: legalLabel, withInset: Values.massiveSpacing)
|
|
legalLabelContainer.pin(.bottom, to: .bottom, of: legalLabel, withInset: isIPhone5OrSmaller ? 6 : 10)
|
|
// Set up top stack view
|
|
let topStackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel, publicKeyLabelContainer ])
|
|
topStackView.axis = .vertical
|
|
topStackView.spacing = isIPhone5OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing
|
|
topStackView.alignment = .fill
|
|
// Set up top stack view container
|
|
let topStackViewContainer = UIView()
|
|
topStackViewContainer.addSubview(topStackView)
|
|
topStackView.pin(.leading, to: .leading, of: topStackViewContainer, withInset: Values.veryLargeSpacing)
|
|
topStackView.pin(.top, to: .top, of: topStackViewContainer)
|
|
topStackViewContainer.pin(.trailing, to: .trailing, of: topStackView, withInset: Values.veryLargeSpacing)
|
|
topStackViewContainer.pin(.bottom, to: .bottom, of: topStackView)
|
|
// Set up main stack view
|
|
let mainStackView = UIStackView(arrangedSubviews: [ topSpacer, topStackViewContainer, bottomSpacer, buttonStackViewContainer, legalLabelContainer ])
|
|
mainStackView.axis = .vertical
|
|
mainStackView.alignment = .fill
|
|
view.addSubview(mainStackView)
|
|
mainStackView.pin(to: view)
|
|
topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true
|
|
// Peform initial seed update
|
|
updateSeed()
|
|
}
|
|
|
|
// MARK: General
|
|
@objc private func enableCopyButton() {
|
|
copyPublicKeyButton.isUserInteractionEnabled = true
|
|
UIView.transition(with: copyPublicKeyButton, duration: 0.25, options: .transitionCrossDissolve, animations: {
|
|
self.copyPublicKeyButton.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal)
|
|
}, completion: nil)
|
|
}
|
|
|
|
// MARK: Updating
|
|
private func updateSeed() {
|
|
seed = Data.getSecureRandomData(ofSize: 16)!
|
|
}
|
|
|
|
private func updateKeyPair() {
|
|
(ed25519KeyPair, x25519KeyPair) = try! Identity.generate(from: seed)
|
|
}
|
|
|
|
private func updatePublicKeyLabel() {
|
|
let hexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey
|
|
let characterCount = hexEncodedPublicKey.count
|
|
var count = 0
|
|
let limit = 32
|
|
func animate() {
|
|
let numberOfIndexesToShuffle = 32 - count
|
|
let indexesToShuffle = (0..<characterCount).shuffled()[0..<numberOfIndexesToShuffle]
|
|
var mangledHexEncodedPublicKey = hexEncodedPublicKey
|
|
for index in indexesToShuffle {
|
|
let startIndex = mangledHexEncodedPublicKey.index(mangledHexEncodedPublicKey.startIndex, offsetBy: index)
|
|
let endIndex = mangledHexEncodedPublicKey.index(after: startIndex)
|
|
mangledHexEncodedPublicKey.replaceSubrange(startIndex..<endIndex, with: "0123456789abcdef__".shuffled()[0..<1])
|
|
}
|
|
count += 1
|
|
if count < limit {
|
|
publicKeyLabel.text = mangledHexEncodedPublicKey
|
|
Timer.scheduledTimer(withTimeInterval: 0.032, repeats: false) { _ in
|
|
animate()
|
|
}
|
|
} else {
|
|
publicKeyLabel.text = hexEncodedPublicKey
|
|
}
|
|
}
|
|
animate()
|
|
}
|
|
|
|
// MARK: Interaction
|
|
@objc private func register() {
|
|
Onboarding.Flow.register.preregister(with: seed, ed25519KeyPair: ed25519KeyPair, x25519KeyPair: x25519KeyPair)
|
|
let displayNameVC = DisplayNameVC()
|
|
navigationController!.pushViewController(displayNameVC, animated: true)
|
|
}
|
|
|
|
@objc private func copyPublicKey() {
|
|
UIPasteboard.general.string = x25519KeyPair.hexEncodedPublicKey
|
|
copyPublicKeyButton.isUserInteractionEnabled = false
|
|
UIView.transition(with: copyPublicKeyButton, duration: 0.25, options: .transitionCrossDissolve, animations: {
|
|
self.copyPublicKeyButton.setTitle(NSLocalizedString("copied", comment: ""), for: UIControl.State.normal)
|
|
}, completion: nil)
|
|
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false)
|
|
}
|
|
|
|
@objc private func handleLegalLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) {
|
|
let urlAsString: String?
|
|
let tosRange = (legalLabel.text! as NSString).range(of: "Terms of Service")
|
|
let eulaRange = (legalLabel.text! as NSString).range(of: "End User License Agreement (EULA)")
|
|
let ppRange = (legalLabel.text! as NSString).range(of: "Privacy Policy")
|
|
let touchInLegalLabelCoordinates = tapGestureRecognizer.location(in: legalLabel)
|
|
let characterIndex = legalLabel.characterIndex(for: touchInLegalLabelCoordinates)
|
|
if tosRange.contains(characterIndex) {
|
|
urlAsString = "https://getsession.org/terms-of-service/"
|
|
} else if eulaRange.contains(characterIndex) {
|
|
urlAsString = "https://getsession.org/terms-of-service/#eula"
|
|
} else if ppRange.contains(characterIndex) {
|
|
urlAsString = "https://getsession.org/privacy-policy/"
|
|
} else {
|
|
urlAsString = nil
|
|
}
|
|
if let urlAsString = urlAsString {
|
|
let url = URL(string: urlAsString)!
|
|
UIApplication.shared.open(url)
|
|
}
|
|
}
|
|
}
|