2022-04-06 07:43:26 +02:00
// C o p y r i g h t © 2 0 2 2 R a n g e p r o o f P t y L t d . A l l r i g h t s r e s e r v e d .
import UIKit
2020-09-24 10:04:36 +02:00
import Sodium
2022-04-06 07:43:26 +02:00
import Curve25519Kit
2022-08-12 05:35:17 +02:00
import SessionUIKit
2022-09-20 08:06:01 +02:00
import SignalUtilitiesKit
2019-12-06 06:42:28 +01:00
2020-02-20 04:37:17 +01:00
final class RegisterVC : BaseVC {
2019-12-06 06:42:28 +01:00
private var seed : Data ! { didSet { updateKeyPair ( ) } }
2020-09-25 03:57:54 +02:00
private var ed25519KeyPair : Sign . KeyPair !
private var x25519KeyPair : ECKeyPair ! { didSet { updatePublicKeyLabel ( ) } }
2019-12-06 06:42:28 +01:00
2022-08-12 05:35:17 +02:00
// MARK: - C o m p o n e n t s
2019-12-06 06:42:28 +01:00
private lazy var publicKeyLabel : UILabel = {
let result = UILabel ( )
2020-06-18 06:41:02 +02:00
result . font = Fonts . spaceMono ( ofSize : isIPhone5OrSmaller ? Values . mediumFontSize : 20 )
2022-09-20 08:06:01 +02:00
result . themeTextColor = . textPrimary
2020-12-17 01:37:53 +01:00
result . accessibilityLabel = " Session ID label "
2022-09-20 08:06:01 +02:00
result . lineBreakMode = . byCharWrapping
result . numberOfLines = 0
2022-08-12 05:35:17 +02:00
2019-12-06 06:42:28 +01:00
return result
} ( )
2022-08-12 05:35:17 +02:00
private lazy var copyPublicKeyButton : OutlineButton = {
let result = OutlineButton ( style : . regular , size : . large )
result . setTitle ( " copy " . localized ( ) , for : . normal )
result . addTarget ( self , action : #selector ( copyPublicKey ) , for : . touchUpInside )
2019-12-06 06:42:28 +01:00
return result
} ( )
2019-12-09 00:27:01 +01:00
private lazy var legalLabel : UILabel = {
let result = UILabel ( )
result . font = . systemFont ( ofSize : Values . verySmallFontSize )
2022-09-20 08:06:01 +02:00
result . themeTextColor = . textPrimary
2020-02-06 03:31:07 +01:00
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 " ) )
2019-12-09 00:27:01 +01:00
result . attributedText = attributedText
result . textAlignment = . center
result . lineBreakMode = . byWordWrapping
2022-09-20 08:06:01 +02:00
result . numberOfLines = 0
2019-12-09 00:27:01 +01:00
return result
} ( )
2022-09-20 08:06:01 +02:00
// MARK: - L i f e c y c l e
2019-12-06 06:42:28 +01:00
override func viewDidLoad ( ) {
2020-02-20 04:37:17 +01:00
super . viewDidLoad ( )
2022-08-31 09:44:44 +02:00
2020-05-30 00:20:30 +02:00
setUpNavBarSessionIcon ( )
2022-08-12 05:35:17 +02:00
2019-12-06 06:42:28 +01:00
// S e t u p t i t l e l a b e l
let titleLabel = UILabel ( )
2020-06-18 06:41:02 +02:00
titleLabel . font = . boldSystemFont ( ofSize : isIPhone5OrSmaller ? Values . largeFontSize : Values . veryLargeFontSize )
2022-08-12 05:35:17 +02:00
titleLabel . text = " vc_register_title " . localized ( )
2022-09-20 08:06:01 +02:00
titleLabel . themeTextColor = . textPrimary
2019-12-06 06:42:28 +01:00
titleLabel . lineBreakMode = . byWordWrapping
2022-08-12 05:35:17 +02:00
titleLabel . numberOfLines = 0
2019-12-06 06:42:28 +01:00
// S e t u p e x p l a n a t i o n l a b e l
let explanationLabel = UILabel ( )
explanationLabel . font = . systemFont ( ofSize : Values . smallFontSize )
2022-08-12 05:35:17 +02:00
explanationLabel . text = " vc_register_explanation " . localized ( )
2022-09-20 08:06:01 +02:00
explanationLabel . themeTextColor = . textPrimary
2019-12-06 06:42:28 +01:00
explanationLabel . lineBreakMode = . byWordWrapping
2022-08-12 05:35:17 +02:00
explanationLabel . numberOfLines = 0
2019-12-06 06:42:28 +01:00
// S e t u p p u b l i c k e y l a b e l c o n t a i n e r
let publicKeyLabelContainer = UIView ( )
publicKeyLabelContainer . addSubview ( publicKeyLabel )
publicKeyLabel . pin ( to : publicKeyLabelContainer , withInset : Values . mediumSpacing )
2021-01-29 01:46:32 +01:00
publicKeyLabelContainer . layer . cornerRadius = TextField . cornerRadius
publicKeyLabelContainer . layer . borderWidth = 1
2022-09-20 08:06:01 +02:00
publicKeyLabelContainer . themeBorderColor = . textPrimary
2022-08-12 05:35:17 +02:00
2019-12-09 00:01:10 +01:00
// S e t u p s p a c e r s
let topSpacer = UIView . vStretchingSpacer ( )
let bottomSpacer = UIView . vStretchingSpacer ( )
2022-08-12 05:35:17 +02:00
2019-12-06 06:42:28 +01:00
// S e t u p r e g i s t e r b u t t o n
2022-08-12 05:35:17 +02:00
let registerButton = OutlineButton ( style : . filled , size : . large )
registerButton . setTitle ( " continue_2 " . localized ( ) , for : . normal )
2019-12-06 06:42:28 +01:00
registerButton . addTarget ( self , action : #selector ( register ) , for : UIControl . Event . touchUpInside )
2022-08-12 05:35:17 +02:00
2019-12-09 00:01:10 +01:00
// S e t u p b u t t o n s t a c k v i e w
let buttonStackView = UIStackView ( arrangedSubviews : [ registerButton , copyPublicKeyButton ] )
buttonStackView . axis = . vertical
2020-06-18 06:41:02 +02:00
buttonStackView . spacing = isIPhone5OrSmaller ? Values . smallSpacing : Values . mediumSpacing
2019-12-09 00:01:10 +01:00
buttonStackView . alignment = . fill
2022-03-02 07:21:10 +01:00
if UIDevice . current . isIPad {
registerButton . set ( . width , to : Values . iPadButtonWidth )
copyPublicKeyButton . set ( . width , to : Values . iPadButtonWidth )
buttonStackView . alignment = . center
}
2022-08-12 05:35:17 +02:00
2019-12-09 00:01:10 +01:00
// S e t u p b u t t o n s t a c k v i e w c o n t a i n e r
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 )
2022-08-12 05:35:17 +02:00
2019-12-06 06:42:28 +01:00
// S e t u p l e g a l l a b e l
2019-12-09 00:27:01 +01:00
legalLabel . isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer ( target : self , action : #selector ( handleLegalLabelTapped ) )
legalLabel . addGestureRecognizer ( tapGestureRecognizer )
2022-08-12 05:35:17 +02:00
2019-12-09 00:27:01 +01:00
// S e t u p l e g a l l a b e l c o n t a i n e r
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 )
2020-06-18 06:41:02 +02:00
legalLabelContainer . pin ( . bottom , to : . bottom , of : legalLabel , withInset : isIPhone5OrSmaller ? 6 : 10 )
2022-08-12 05:35:17 +02:00
2019-12-09 00:01:10 +01:00
// S e t u p t o p s t a c k v i e w
let topStackView = UIStackView ( arrangedSubviews : [ titleLabel , explanationLabel , publicKeyLabelContainer ] )
topStackView . axis = . vertical
2020-06-18 06:41:02 +02:00
topStackView . spacing = isIPhone5OrSmaller ? Values . smallSpacing : Values . veryLargeSpacing
2019-12-09 00:01:10 +01:00
topStackView . alignment = . fill
2022-08-12 05:35:17 +02:00
2019-12-09 00:01:10 +01:00
// S e t u p t o p s t a c k v i e w c o n t a i n e r
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 )
2022-08-12 05:35:17 +02:00
2019-12-06 06:42:28 +01:00
// S e t u p m a i n s t a c k v i e w
2019-12-09 00:27:01 +01:00
let mainStackView = UIStackView ( arrangedSubviews : [ topSpacer , topStackViewContainer , bottomSpacer , buttonStackViewContainer , legalLabelContainer ] )
2019-12-06 06:42:28 +01:00
mainStackView . axis = . vertical
mainStackView . alignment = . fill
view . addSubview ( mainStackView )
mainStackView . pin ( to : view )
2019-12-09 00:01:10 +01:00
topSpacer . heightAnchor . constraint ( equalTo : bottomSpacer . heightAnchor , multiplier : 1 ) . isActive = true
2022-08-12 05:35:17 +02:00
2019-12-06 06:42:28 +01:00
// P e f o r m i n i t i a l s e e d u p d a t e
updateSeed ( )
}
// MARK: G e n e r a l
@objc private func enableCopyButton ( ) {
copyPublicKeyButton . isUserInteractionEnabled = true
UIView . transition ( with : copyPublicKeyButton , duration : 0.25 , options : . transitionCrossDissolve , animations : {
2020-07-27 03:32:47 +02:00
self . copyPublicKeyButton . setTitle ( NSLocalizedString ( " copy " , comment : " " ) , for : UIControl . State . normal )
2019-12-06 06:42:28 +01:00
} , completion : nil )
}
// MARK: U p d a t i n g
private func updateSeed ( ) {
2020-09-24 10:04:36 +02:00
seed = Data . getSecureRandomData ( ofSize : 16 ) !
2019-12-06 06:42:28 +01:00
}
private func updateKeyPair ( ) {
2022-04-01 08:22:45 +02:00
( ed25519KeyPair , x25519KeyPair ) = try ! Identity . generate ( from : seed )
2019-12-06 06:42:28 +01:00
}
private func updatePublicKeyLabel ( ) {
2020-09-25 03:57:54 +02:00
let hexEncodedPublicKey = x25519KeyPair . hexEncodedPublicKey
2020-01-08 06:10:12 +01:00
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 ( )
2019-12-06 06:42:28 +01:00
}
// MARK: I n t e r a c t i o n
@objc private func register ( ) {
2021-02-23 03:53:30 +01:00
Onboarding . Flow . register . preregister ( with : seed , ed25519KeyPair : ed25519KeyPair , x25519KeyPair : x25519KeyPair )
2019-12-09 01:30:26 +01:00
let displayNameVC = DisplayNameVC ( )
navigationController ! . pushViewController ( displayNameVC , animated : true )
2019-12-06 06:42:28 +01:00
}
@objc private func copyPublicKey ( ) {
2020-09-25 03:57:54 +02:00
UIPasteboard . general . string = x25519KeyPair . hexEncodedPublicKey
2019-12-06 06:42:28 +01:00
copyPublicKeyButton . isUserInteractionEnabled = false
UIView . transition ( with : copyPublicKeyButton , duration : 0.25 , options : . transitionCrossDissolve , animations : {
2021-05-07 03:05:16 +02:00
self . copyPublicKeyButton . setTitle ( NSLocalizedString ( " copied " , comment : " " ) , for : UIControl . State . normal )
2019-12-06 06:42:28 +01:00
} , completion : nil )
Timer . scheduledTimer ( timeInterval : 4 , target : self , selector : #selector ( enableCopyButton ) , userInfo : nil , repeats : false )
}
2019-12-09 00:27:01 +01:00
@objc private func handleLegalLabelTapped ( _ tapGestureRecognizer : UITapGestureRecognizer ) {
2020-02-06 03:31:07 +01:00
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 ) {
2020-05-28 06:38:33 +02:00
urlAsString = " https://getsession.org/terms-of-service/ "
2020-02-06 03:31:07 +01:00
} else if eulaRange . contains ( characterIndex ) {
2020-05-28 06:38:33 +02:00
urlAsString = " https://getsession.org/terms-of-service/#eula "
2020-02-06 03:31:07 +01:00
} else if ppRange . contains ( characterIndex ) {
2020-05-28 06:38:33 +02:00
urlAsString = " https://getsession.org/privacy-policy/ "
2020-02-06 03:31:07 +01:00
} else {
urlAsString = nil
}
if let urlAsString = urlAsString {
let url = URL ( string : urlAsString ) !
UIApplication . shared . open ( url )
}
2019-12-09 00:27:01 +01:00
}
2019-12-06 06:42:28 +01:00
}