@@ -6,7 +6,7 @@ import Prelude
7import BW (ApiService, CryptoFunctions, Services, CryptoService)
7import BW (ApiService, CryptoFunctions, Services, CryptoService)
8import BW as WB
8import BW as WB
9−import BW.Logic (bwPasswordStringHash, decodeCipher, decrypt, encodeCipher, hashPassword, liftPromise)
9+import BW.Logic (bwPasswordStringHash, decodeCipher, decrypt, encodeCipher, hashPassword, liftPromise, supportedCipher)
10import BW.Logic as Logic
10import BW.Logic as Logic
11import BW.Types (CipherResponse, Email(..), Password(..), Urls, cipherTypeCard, cipherTypeIdentity, cipherTypeLogin, cipherTypeSecureNote, fromTwoFactorProviderType)
11import BW.Types (CipherResponse, Email(..), Password(..), Urls, cipherTypeCard, cipherTypeIdentity, cipherTypeLogin, cipherTypeSecureNote, fromTwoFactorProviderType)
12import Bridge as Bridge
12import Bridge as Bridge
@@ -16,6 +16,7 @@ import Data.Array as Array
16import Data.Clipboard as Clipboard
16import Data.Clipboard as Clipboard
17import Data.DateTime (DateTime)
17import Data.DateTime (DateTime)
18import Data.Either (Either(..))
18import Data.Either (Either(..))
19+import Data.Foldable (for_)
19import Data.HCaptcha (bindHCaptchToken)
20import Data.HCaptcha (bindHCaptchToken)
20import Data.JNullable (jnull, nullify)
21import Data.JNullable (jnull, nullify)
21import Data.JNullable as JNullable
22import Data.JNullable as JNullable
@@ -61,19 +62,19 @@ main = do
62 runAff act = runElmAff app $ run $ act
63 runAff act = runElmAff app $ run $ act
65− forall a.
66+ :: forall a
67− ( app :: Reader Elm
68+ ( app :: Reader Elm
68− , aff :: Aff
69+ , aff :: Aff
69− , effect :: Effect
70+ , effect :: Effect
70− , crypto :: Reader CryptoService
71+ , crypto :: Reader CryptoService
71− , storage :: Reader Storage
72+ , storage :: Reader Storage
72− , services :: Reader Services
73+ , services :: Reader Services
73− , cryptoFunctions :: Reader CryptoFunctions
74+ , cryptoFunctions :: Reader CryptoFunctions
76− Run (EFFECT + AFF + ()) a
77+ -> Run (EFFECT + AFF + ()) a
78 runReaderAt (Proxy :: _ "app") app
79 runReaderAt (Proxy :: _ "app") app
79 $ runReaderAt (Proxy :: _ "crypto") services.crypto
80 $ runReaderAt (Proxy :: _ "crypto") services.crypto
@@ -82,19 +83,19 @@ main = do
82 $ runReaderAt (Proxy :: _ "cryptoFunctions") services.cryptoFunctions
83 $ runReaderAt (Proxy :: _ "cryptoFunctions") services.cryptoFunctions
85− runWithDecryptionKey ::
86+ runWithDecryptionKey
87− ( app :: Reader Elm
88+ ( app :: Reader Elm
88− , aff :: Aff
89+ , aff :: Aff
89− , effect :: Effect
90+ , effect :: Effect
90− , key :: Reader SymmetricCryptoKey
91+ , key :: Reader SymmetricCryptoKey
91− , crypto :: Reader CryptoService
92+ , crypto :: Reader CryptoService
92− , storage :: Reader Storage
93+ , storage :: Reader Storage
93− , services :: Reader Services
94+ , services :: Reader Services
94− , cryptoFunctions :: Reader CryptoFunctions
95+ , cryptoFunctions :: Reader CryptoFunctions
97− Effect Unit
98+ -> Effect Unit
98 runWithDecryptionKey act = do
99 runWithDecryptionKey act = do
99 maybeKey <- Ref.read masterKeyRef
100 maybeKey <- Ref.read masterKeyRef
@@ -182,9 +183,9 @@ main = do
182 Bridge.Init -> do
183 Bridge.Init -> do
183 Storage.get storage TokenKey
184 Storage.get storage TokenKey
184 >>= \x ->
185 >>= \x ->
185− Elm.send app case x of
186+ Elm.send app case x of
186− Just _ -> Bridge.LoginSuccessful
187+ Just _ -> Bridge.LoginSuccessful
187− Nothing -> Bridge.NeedsLogin
188+ Nothing -> Bridge.NeedsLogin
188 Bridge.RequestCipher id ->
189 Bridge.RequestCipher id ->
189 runWithDecryptionKey do
190 runWithDecryptionKey do
190 sync <- getOrReset SyncKey
191 sync <- getOrReset SyncKey
@@ -192,8 +193,7 @@ main = do
192 Nothing -> pure unit
193 Nothing -> pure unit
193 Just cipherResponse -> do
194 Just cipherResponse -> do
194 cipher <- decodeCipher cipherResponse
195 cipher <- decodeCipher cipherResponse
195− send $ Bridge.LoadCipher cipher
196+ for_ cipher $ send <<< Bridge.LoadCipher
197 pure unit
197 pure unit
198 Bridge.NeedEmail ->
198 Bridge.NeedEmail ->
199 runWithDecryptionKey do
199 runWithDecryptionKey do
@@ -209,7 +209,7 @@ main = do
209 api <- getAuthedApi
209 api <- getAuthedApi
210 cipher <- encodeCipher fullCipher
210 cipher <- encodeCipher fullCipher
211 newCipher <- liftPromise (api.putCipher cipher) >>= decodeCipher
211 newCipher <- liftPromise (api.putCipher cipher) >>= decodeCipher
212− send $ Bridge.CipherChanged newCipher
212+ for_ newCipher $ send <<< Bridge.CipherChanged
213 performSync
213 performSync
214 pure unit
214 pure unit
215 Bridge.GeneratePassword cfg ->
215 Bridge.GeneratePassword cfg ->
@@ -222,7 +222,7 @@ main = do
222 api <- getAuthedApi
222 api <- getAuthedApi
223 cipher <- encodeCipher fullCipher
223 cipher <- encodeCipher fullCipher
224 newCipher <- liftPromise (api.postCipherCreate cipher) >>= decodeCipher
224 newCipher <- liftPromise (api.postCipherCreate cipher) >>= decodeCipher
225− send $ Bridge.CipherChanged newCipher
225+ for_ newCipher $ send <<< Bridge.CipherChanged
226 performSync
226 performSync
227 pure unit
227 pure unit
228 Bridge.DeleteCipher c@(Bridge.FullCipher { id }) ->
228 Bridge.DeleteCipher c@(Bridge.FullCipher { id }) ->
@@ -240,14 +240,20 @@ main = do
240 interval = totpService.getTimeInterval totp
240 interval = totpService.getTimeInterval totp
241 send $ Bridge.Totp
241 send $ Bridge.Totp
242 $ Bridge.Sub_Totp
242 $ Bridge.Sub_Totp
243− { interval, code, source: totp
245+ , source: totp
245 pure unit
247 pure unit
246 Bridge.ChooseSecondFactor
248 Bridge.ChooseSecondFactor
247 ( Bridge.Cmd_ChooseSecondFactor
249 ( Bridge.Cmd_ChooseSecondFactor
248− { email: email', factor, server, password, requestFromServer
254+ , requestFromServer
251 when requestFromServer
257 when requestFromServer
253 email = Email email'
259 email = Email email'
@@ -264,17 +270,18 @@ main = do
264 pure unit
270 pure unit
265 _ -> pure unit
271 _ -> pure unit
267−processCipher ::
273+processCipher
268− forall r.
274+ :: forall r
269− CipherResponse ->
275+ . CipherResponse
271− ( crypto :: Reader CryptoService
277+ ( crypto :: Reader CryptoService
272− , key :: Reader SymmetricCryptoKey
278+ , key :: Reader SymmetricCryptoKey
273− , aff :: Aff
279+ , aff :: Aff
274− , effect :: Effect
280+ , effect :: Effect
277− { cipher :: Bridge.Sub_LoadCiphers, date :: DateTime }
283+ (Maybe { cipher :: Bridge.Sub_LoadCiphers, date :: DateTime })
284+processCipher cipher | not (supportedCipher cipher) = pure Nothing
278processCipher cipher = do
285processCipher cipher = do
279 name <- decrypt cipher.name
286 name <- decrypt cipher.name
280 cipherType <- case cipher.type of
287 cipherType <- case cipher.type of
@@ -289,7 +296,9 @@ processCipher cipher = do
289 n -> liftEffect $ throw $ "Unsupported cipher type: " <> show n
296 n -> liftEffect $ throw $ "Unsupported cipher type: " <> show n
290 date <- liftEffect $ maybe (pure bottom) (Timestamp.toDateTime) $ JNullable.toMaybe cipher.revisionDate
297 date <- liftEffect $ maybe (pure bottom) (Timestamp.toDateTime) $ JNullable.toMaybe cipher.revisionDate
292− $ { cipher:
301+ { cipher:
293 Bridge.Sub_LoadCiphers
302 Bridge.Sub_LoadCiphers
294 { name: name
303 { name: name
295 , date: maybe "" Timestamp.toLocalDateTimeString $ JNullable.toMaybe cipher.revisionDate
304 , date: maybe "" Timestamp.toLocalDateTimeString $ JNullable.toMaybe cipher.revisionDate
@@ -323,18 +332,18 @@ baseUrl server =
323 , keyConnector: jnull
332 , keyConnector: jnull
326−getOrReset ::
335+getOrReset
327− forall k t r.
336+ :: forall k t r
328− StorageKey k t =>
337+ . StorageKey k t
329− DecodeJson t =>
338+ => DecodeJson t
332− ( storage :: Reader Storage
341+ ( storage :: Reader Storage
333− , app :: Reader Elm
342+ , app :: Reader Elm
334− , effect :: Effect
343+ , effect :: Effect
338getOrReset key = do
347getOrReset key = do
339 storage <- askAt (Proxy :: _ "storage")
348 storage <- askAt (Proxy :: _ "storage")
340 app <- askAt (Proxy :: _ "app")
349 app <- askAt (Proxy :: _ "app")
@@ -345,69 +354,69 @@ getOrReset key = do
345 Exc.throw "Encountered an internal error. Resetting the app."
354 Exc.throw "Encountered an internal error. Resetting the app."
346 liftEffect $ try (Storage.get storage key)
355 liftEffect $ try (Storage.get storage key)
347 >>= \x -> case x of
356 >>= \x -> case x of
348− Left err -> do
357+ Left err -> do
349− log $ show err
358+ log $ show err
350− handleError
359+ handleError
351− Right Nothing -> handleError
360+ Right Nothing -> handleError
352− Right (Just y) -> pure y
361+ Right (Just y) -> pure y
354−getAuthedApi ::
363+getAuthedApi
355− forall r.
364+ :: forall r
357− ( storage :: Reader Storage
366+ ( storage :: Reader Storage
358− , app :: Reader Elm
367+ , app :: Reader Elm
359− , aff :: Aff
368+ , aff :: Aff
360− , effect :: Effect
369+ , effect :: Effect
361− , services :: Reader Services
370+ , services :: Reader Services
364− ApiService
373+ ApiService
365getAuthedApi = do
374getAuthedApi = do
366 services <- askAt (Proxy :: _ "services")
375 services <- askAt (Proxy :: _ "services")
367 token <- getOrReset TokenKey
376 token <- getOrReset TokenKey
368 url <- getOrReset UrlsKey
377 url <- getOrReset UrlsKey
369 liftPromise $ services.getApi (baseUrl url) (nullify token)
378 liftPromise $ services.getApi (baseUrl url) (nullify token)
371−requestMasterPassword ::
380+requestMasterPassword
372− forall r.
381+ :: forall r
374− ( storage :: Reader Storage
383+ ( storage :: Reader Storage
375− , app :: Reader Elm
384+ , app :: Reader Elm
376− , effect :: Effect
385+ , effect :: Effect
380requestMasterPassword = do
389requestMasterPassword = do
381 url <- getOrReset UrlsKey
390 url <- getOrReset UrlsKey
382 sync <- getOrReset SyncKey
391 sync <- getOrReset SyncKey
383 send $ Bridge.NeedsMasterPassword $ Bridge.Sub_NeedsMasterPassword { server: url, login: sync.profile.email }
392 send $ Bridge.NeedsMasterPassword $ Bridge.Sub_NeedsMasterPassword { server: url, login: sync.profile.email }
386− forall r.
395+ :: forall r
387− Bridge.Sub ->
396+ . Bridge.Sub
389− ( app :: Reader Elm
398+ ( app :: Reader Elm
390− , effect :: Effect
399+ , effect :: Effect
394send sub = do
403send sub = do
395 app <- askAt (Proxy :: _ "app")
404 app <- askAt (Proxy :: _ "app")
396 liftEffect $ Elm.send app sub
405 liftEffect $ Elm.send app sub
398−performSync ::
407+performSync
399− forall r.
408+ :: forall r
401− ( storage :: Reader Storage
410+ ( storage :: Reader Storage
402− , app :: Reader Elm
411+ , app :: Reader Elm
403− , aff :: Aff
412+ , aff :: Aff
404− , effect :: Effect
413+ , effect :: Effect
405− , services :: Reader Services
414+ , services :: Reader Services
406− , crypto :: Reader CryptoService
415+ , crypto :: Reader CryptoService
407− , key :: Reader SymmetricCryptoKey
416+ , key :: Reader SymmetricCryptoKey
411performSync = do
420performSync = do
412 api <- getAuthedApi
421 api <- getAuthedApi
413 storage <- askAt (Proxy :: _ "storage")
422 storage <- askAt (Proxy :: _ "storage")
@@ -415,22 +424,22 @@ performSync = do
415 liftEffect $ Storage.store storage SyncKey newSync
424 liftEffect $ Storage.store storage SyncKey newSync
416 sendCiphers
425 sendCiphers
418−sendCiphers ::
427+sendCiphers
419− forall r.
428+ :: forall r
421− ( storage :: Reader Storage
430+ ( storage :: Reader Storage
422− , app :: Reader Elm
431+ , app :: Reader Elm
423− , aff :: Aff
432+ , aff :: Aff
424− , effect :: Effect
433+ , effect :: Effect
425− , services :: Reader Services
434+ , services :: Reader Services
426− , crypto :: Reader CryptoService
435+ , crypto :: Reader CryptoService
427− , key :: Reader SymmetricCryptoKey
436+ , key :: Reader SymmetricCryptoKey
431sendCiphers = do
440sendCiphers = do
432 sync <- getOrReset SyncKey
441 sync <- getOrReset SyncKey
433− ciphers <- traverse processCipher sync.ciphers
442+ ciphers <- Array.catMaybes <$> traverse processCipher sync.ciphers
435 sortedCiphers = Array.sortWith (_.date >>> Down) ciphers
444 sortedCiphers = Array.sortWith (_.date >>> Down) ciphers
436 send $ Bridge.LoadCiphers $ Bridge.Sub_LoadCiphers_List $ map _.cipher sortedCiphers
445 send $ Bridge.LoadCiphers $ Bridge.Sub_LoadCiphers_List $ map _.cipher sortedCiphers