on master help sign in
Ignore organization permissions (#43)
6769c73iko
backend/BW/Logic.purs+11−2
@@ -335,6 +335,13 @@ encodeCipher
335 , reprompt
335 , reprompt
336 }
336 }
337
337
338+-- | Check if the cipher is supported by Warden.
339+supportedCipher :: CipherResponse -> Boolean
340+-- We do not support organizations since that requires managing a separate set of
341+-- encryption keys
342+supportedCipher { organizationId } | Just _ <- JNullable.toMaybe organizationId = false
343+supportedCipher _ = true
344+
338decodeCipher
345decodeCipher
339 :: forall r
346 :: forall r
340 . CipherResponse
347 . CipherResponse
@@ -345,7 +352,9 @@ decodeCipher
345 , effect :: Effect
352 , effect :: Effect
346 | r
353 | r
347 )
354 )
348− Bridge.FullCipher
355+ (Maybe Bridge.FullCipher)
356+decodeCipher cipher | not (supportedCipher cipher) =
357+ pure $ Nothing
349decodeCipher cipher = do
358decodeCipher cipher = do
350 name <- decrypt cipher.name
359 name <- decrypt cipher.name
351 cipherType <- case cipher.type of
360 cipherType <- case cipher.type of
@@ -429,7 +438,7 @@ decodeCipher cipher = do
429 , username
438 , username
430 }
439 }
431 n -> liftEffect $ throwError $ error $ "Unsupported cipher type: " <> show n
440 n -> liftEffect $ throwError $ error $ "Unsupported cipher type: " <> show n
432− pure
441+ pure $ Just
433 $ wrap
442 $ wrap
434 { cipher: cipherType
443 { cipher: cipherType
435 , name
444 , name
backend/BW/Types.purs+2−2
@@ -48,7 +48,7 @@ type ProfileResponse =
48 , email :: String
48 , email :: String
49 , emailVerified :: Boolean
49 , emailVerified :: Boolean
50 , masterPasswordHint :: JNullable String
50 , masterPasswordHint :: JNullable String
51− , premiumPersonally :: Boolean
51+ -- , premiumPersonally :: Boolean
52 -- , premiumFromOrganization :: Boolean
52 -- , premiumFromOrganization :: Boolean
53 , culture :: JNullable String
53 , culture :: JNullable String
54 , twoFactorEnabled :: Boolean
54 , twoFactorEnabled :: Boolean
@@ -57,7 +57,7 @@ type ProfileResponse =
57 , securityStamp :: JNullable String
57 , securityStamp :: JNullable String
58 , forcePasswordReset :: Boolean
58 , forcePasswordReset :: Boolean
59 , usesKeyConnector :: Boolean
59 , usesKeyConnector :: Boolean
60− , organizations :: Array ProfileOrganizationResponse
60+ -- , organizations :: Array ProfileOrganizationResponse
61 , providers :: Array ProfileProviderResponse
61 , providers :: Array ProfileProviderResponse
62 , providerOrganizations :: Array ProfileProviderOrganizationResponse
62 , providerOrganizations :: Array ProfileProviderOrganizationResponse
63 }
63 }
backend/Main.purs+132−123
@@ -6,7 +6,7 @@ import Prelude
6
6
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
61 let
62 let
62 runAff act = runElmAff app $ run $ act
63 runAff act = runElmAff app $ run $ act
63
64
64− run ::
65+ run
65− forall a.
66+ :: forall a
66− Run
67+ . Run
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
74− )
75+ )
75− a ->
76+ a
76− Run (EFFECT + AFF + ()) a
77+ -> Run (EFFECT + AFF + ()) a
77 run act =
78 run act =
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
83 $ act
84 $ act
84
85
85− runWithDecryptionKey ::
86+ runWithDecryptionKey
86− Run
87+ :: Run
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
95− )
96+ )
96− Unit ->
97+ Unit
97− Effect Unit
98+ -> Effect Unit
98 runWithDecryptionKey act = do
99 runWithDecryptionKey act = do
99 maybeKey <- Ref.read masterKeyRef
100 maybeKey <- Ref.read masterKeyRef
100 runAff
101 runAff
@@ -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
196− pure unit
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
244+ , code
243− { interval, code, source: totp
245+ , source: totp
244 }
246 }
245 pure unit
247 pure unit
246 Bridge.ChooseSecondFactor
248 Bridge.ChooseSecondFactor
247 ( Bridge.Cmd_ChooseSecondFactor
249 ( Bridge.Cmd_ChooseSecondFactor
250+ { email: email'
251+ , factor
252+ , server
253+ , password
248− { email: email', factor, server, password, requestFromServer
254+ , requestFromServer
249− }
255+ }
250− ) ->
256+ ) ->
251 when requestFromServer
257 when requestFromServer
252 let
258 let
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
266
272
267−processCipher ::
273+processCipher
268− forall r.
274+ :: forall r
269− CipherResponse ->
275+ . CipherResponse
270− Run
276+ -> Run
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
275− | r
281+ | r
276− )
282+ )
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
291 pure
298 pure
299+ $ Just
300+ $
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
324 }
333 }
325
334
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
330− k ->
339+ => k
331− Run
340+ -> Run
332− ( storage :: Reader Storage
341+ ( storage :: Reader Storage
333− , app :: Reader Elm
342+ , app :: Reader Elm
334− , effect :: Effect
343+ , effect :: Effect
335− | r
344+ | r
336− )
345+ )
337− t
346+ t
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
353
362
354−getAuthedApi ::
363+getAuthedApi
355− forall r.
364+ :: forall r
356− Run
365+ . Run
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
362− | r
371+ | r
363− )
372+ )
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)
370
379
371−requestMasterPassword ::
380+requestMasterPassword
372− forall r.
381+ :: forall r
373− Run
382+ . Run
374− ( storage :: Reader Storage
383+ ( storage :: Reader Storage
375− , app :: Reader Elm
384+ , app :: Reader Elm
376− , effect :: Effect
385+ , effect :: Effect
377− | r
386+ | r
378− )
387+ )
379− Unit
388+ Unit
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 }
384
393
385−send ::
394+send
386− forall r.
395+ :: forall r
387− Bridge.Sub ->
396+ . Bridge.Sub
388− Run
397+ -> Run
389− ( app :: Reader Elm
398+ ( app :: Reader Elm
390− , effect :: Effect
399+ , effect :: Effect
391− | r
400+ | r
392− )
401+ )
393− Unit
402+ Unit
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
397
406
398−performSync ::
407+performSync
399− forall r.
408+ :: forall r
400− Run
409+ . Run
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
408− | r
417+ | r
409− )
418+ )
410− Unit
419+ Unit
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
417
426
418−sendCiphers ::
427+sendCiphers
419− forall r.
428+ :: forall r
420− Run
429+ . Run
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
428− | r
437+ | r
429− )
438+ )
430− Unit
439+ Unit
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
434 let
443 let
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
clickable.yaml+10−8
@@ -3,14 +3,16 @@ builder: custom
3build: $SRC_DIR/build.sh
3build: $SRC_DIR/build.sh
4kill: webapp-container*
4kill: webapp-container*
5image_setup:
5image_setup:
6− env: {}
6+ env:
7− # DEB_URL: http://archive.ubuntu.com/ubuntu
7+ NIX_PATH: nixpkgs=https://github.com/NixOS/nixpkgs/archive/4d2b37a84fad1091b9de401eb450aae66f1a741e.tar.gz
8− # HOST_ARCH: amd64
8+ HOME: /home/phablet
9−
9+ PATH: /home/phablet/.nix-profile/bin:$PATH
10− # PATH: /opt/someprogram/bin:$PATH
11 run:
10 run:
12−
11+ - mkdir -m 0755 /nix && chown phablet /nix
13− - (cd /tmp && curl -L -o elm.gz https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz && gunzip elm.gz && chmod +x elm && mv elm /usr/local/bin/)
12+ - curl -L https://nixos.org/nix/install >/tmp/install-nix.sh
14− - npm install -g spago esbuild purescript terser --unsafe-perm=true
13+ - su -l -m phablet -s /bin/bash -c "mkdir -p /home/phablet/.config/nix; echo \"sandbox = false\" >/home/phablet/.config/nix/nix.conf"
14+ - su -l -m phablet -s /bin/bash -c "sh /tmp/install-nix.sh --no-daemon --yes --no-channel-add --no-modify-profile"
15+ - echo "export PATH=/home/phablet/.nix-profile/bin:\$PATH" >>/home/phablet/.profile
16+ - su -l -m phablet -s /bin/bash -c "nix-env -f \"<nixpkgs>\" -iA purescript elmPackages.elm nodePackages.terser esbuild spago"
15
17
16restrict_arch: all
18restrict_arch: all
dev/start-chrome.sh+3−1
@@ -1,6 +1,8 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+if test -x "$(which chromium)"; then
4+ chromium --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security
3−if test -f /Applications/Chromium.app/Contents/MacOS/Chromium; then
5+elif test -x /Applications/Chromium.app/Contents/MacOS/Chromium; then
4 /Applications/Chromium.app/Contents/MacOS/Chromium --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security
6 /Applications/Chromium.app/Contents/MacOS/Chromium --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security
5else
7else
6 flatpak run com.github.Eloston.UngoogledChromium --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security
8 flatpak run com.github.Eloston.UngoogledChromium --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security