on master help sign in
.github/FUNDING.yml+1−1
since splitsnapshots
unifiedsplit
@@ -1 +1 @@
1−custom: https://iko.soy/donate
1+custom: ["https://iko.soy/donate"]
.github/workflows/build.yaml+47−7
@@ -5,13 +5,21 @@ on:
5 branches: ["master"]
5 branches: ["master"]
6 pull_request:
6 pull_request:
7 branches: ["master"]
7 branches: ["master"]
8+ release:
9+ types: [prereleased]
8
10
9jobs:
11jobs:
10 build:
12 build:
11 runs-on: ubuntu-latest
13 runs-on: ubuntu-latest
12
14
13 steps:
15 steps:
14− - uses: cachix/install-nix-action@v18
16+ - uses: cachix/install-nix-action@v19
17+
18+ - name: Cachix
19+ uses: cachix/cachix-action@v12
20+ with:
21+ name: iko
22+ authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
15
23
16 - uses: actions/checkout@v3
24 - uses: actions/checkout@v3
17 with:
25 with:
@@ -19,20 +27,26 @@ jobs:
19
27
20 - name: Install clickable
28 - name: Install clickable
21 run: |
29 run: |
30+ docker --version
22 sudo apt install adb git python3 python3-pip python3-setuptools
31 sudo apt install adb git python3 python3-pip python3-setuptools
23− pip3 install --user clickable-ut --upgrade
32+ pip3 install --user clickable-ut==7.10.0 --upgrade
24 echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc
33 echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc
25
34
26− - name: Build bw libraries
35+ - name: Build artifacts
27− run: ./dev/build-bw.sh
36+ run: ./dev/build.sh
28
37
29 - name: Build Warden
38 - name: Build Warden
30− run: clickable build --output dist
39+ run: clickable build --output click
40+
41+ - uses: actions/upload-artifact@v3
42+ with:
43+ name: click
44+ path: click/*
31
45
32 - uses: actions/upload-artifact@v3
46 - uses: actions/upload-artifact@v3
33 with:
47 with:
34− name: warden
48+ name: dist
35− path: dist/*
49+ path: dist
36
50
37 # Tests
51 # Tests
38
52
@@ -55,3 +69,29 @@ jobs:
55 with:
69 with:
56 name: playwright-report
70 name: playwright-report
57 path: tests/playwright-report/
71 path: tests/playwright-report/
72+
73+ # Upload release
74+
75+ - name: Zip Release Assets
76+ if: github.event_name == 'release'
77+ shell: bash
78+ run: |
79+ cd dist/
80+ zip -r ../../../../dist.zip .
81+
82+ - name: Upload dist to release
83+ if: github.event_name == 'release'
84+ uses: svenstaro/upload-release-action@2.4.1
85+ with:
86+ repo_token: ${{ secrets.GITHUB_TOKEN }}
87+ file: dist.zip
88+ tag: ${{ github.ref }}
89+
90+ - name: Upload click to release
91+ if: github.event_name == 'release'
92+ uses: svenstaro/upload-release-action@2.4.1
93+ with:
94+ repo_token: ${{ secrets.GITHUB_TOKEN }}
95+ file: build/all/app/*.click
96+ tag: ${{ github.ref }}
97+ file_glob: true
.gitignore+4−1
@@ -7,7 +7,6 @@ static/backend.js
7.spago
7.spago
8output
8output
9.psc-ide-port
9.psc-ide-port
10−backend.js
11elm.js
10elm.js
12output-es
11output-es
13elm-stuff
12elm-stuff
@@ -17,3 +16,7 @@ node_modules/
17/tests/playwright/.cache/
16/tests/playwright/.cache/
18generated-docs
17generated-docs
19backend.js.map
18backend.js.map
19+.spago2nix
20+backend.js
21+vanilla
22+dist
.gitmodulesdeleted−6
@@ -1,6 +0,0 @@
1−[submodule "deps/bw"]
2− path = deps/bw
3− url = https://github.com/bitwarden/clients.git
4−[submodule "vanilla"]
5− path = vanilla
6− url = https://github.com/ilyakooo0/vanilla-compiled.git
.helix/languages.tomlnew file+3
@@ -0,0 +1,3 @@
1+[[language]]
2+name = "nix"
3+auto-format = true
backend-main.jsnew file+3
@@ -0,0 +1,3 @@
1+import * as Main from "./backend/Main/index.js"
2+
3+Main.main()
backend/BW.js+34−54
@@ -1,27 +1,29 @@
1−import { StateFactory } from "../../deps/bw/libs/shared/dist/src/factories/stateFactory";
1+import { StateFactory } from "../../bw/factories/stateFactory";
2−import { GlobalState } from "../../deps/bw/libs/shared/dist/src/models/domain/globalState";
2+import { GlobalState } from "../../bw/models/domain/global-state";
3−import { ApiService } from "../../deps/bw/libs/shared/dist/src/services/api.service";
3+import { ApiService } from "../../bw/services/api.service";
4−import { AppIdService } from "../../deps/bw/libs/shared/dist/src/services/appId.service";
4+import { AppIdService } from "../../bw/services/appId.service";
5−import { ConsoleLogService } from "../../deps/bw/libs/shared/dist/src/services/consoleLog.service";
5+import { ConsoleLogService } from "../../bw/services/consoleLog.service";
6−import { EnvironmentService } from "../../deps/bw/libs/shared/dist/src/services/environment.service";
6+import { EnvironmentService } from "../../bw/services/environment.service";
7−import { StateMigrationService } from "../../deps/bw/libs/shared/dist/src/services/stateMigration.service";
7+import { StateMigrationService } from "../../bw/services/stateMigration.service";
8−import { TokenService } from "../../deps/bw/libs/shared/dist/src/services/token.service";
8+import { TokenService } from "../../bw/services/token.service";
9−import { WebCryptoFunctionService } from "../../deps/bw/libs/shared/dist/src/services/webCryptoFunction.service";
9+import { WebCryptoFunctionService } from "../../bw/services/webCryptoFunction.service";
10−import { Account, AccountProfile, AccountTokens } from "../../deps/bw/libs/shared/dist/src/models/domain/account";
10+import { Account, AccountProfile, AccountTokens } from "../../bw/models/domain/account";
11−
11+import {MemoryStorageService} from "../../bw/services/memoryStorage.service"
12+
12−// import BrowserStorageService from "../../../../deps/bw/libs/shared/dist/src/services/browserStorage.service";
13+// import BrowserStorageService from "../../../../bw/services/browserStorage.service";
13−import { CryptoService } from "../../deps/bw/libs/shared/dist/src/services/crypto.service";
14+import { CryptoService } from "../../bw/services/crypto.service";
14−
15+
15−import { I18nService } from "../../deps/bw/libs/shared/dist/src/services/i18n.service";
16+import { I18nService } from "../../bw/services/i18n.service";
16−import { StateService as BaseStateService } from "../../deps/bw/libs/shared/dist/src/services/state.service";
17+import { StateService as BaseStateService } from "../../bw/services/state.service";
17−import { PasswordTokenRequest } from "../../deps/bw/libs/shared/dist/src/models/request/identityToken/passwordTokenRequest";
18+import { PasswordTokenRequest } from "../../bw/models/request/identity-token/password-token.request";
18−import { TokenRequestTwoFactor } from "../../deps/bw/libs/common/src/models/request/identityToken/tokenRequestTwoFactor";
19+import { TokenTwoFactorRequest} from "../../bw/models/request/identity-token/token-two-factor.request";
19−import { CipherRequest } from "../../deps/bw/libs/common/src/models/request/cipherRequest";
20+import { CipherRequest } from "../../bw/vault/models/request/cipher.request";
20−import { CipherCreateRequest } from "../../deps/bw/libs/common/src/models/request/cipherCreateRequest";
21+import { CipherCreateRequest } from "../../bw/vault/models/request/cipher-create.request";
21−import { Cipher } from "../../deps/bw/libs/common/src/models/domain/cipher";
22+import { Cipher } from "../../bw/vault/models/domain/cipher";
22−import { CipherData } from "../../deps/bw/libs/common/src/models/data/cipherData";
23+import { CipherData } from "../../bw/vault/models/data/cipher.data";
23−import { PasswordGenerationService } from "../../deps/bw/libs/common/src/services/passwordGeneration.service";
24+import { PasswordGenerationService } from "../../bw/services/passwordGeneration.service";
24−import { TotpService } from "../../deps/bw/libs/shared/dist/src/services/totp.service"
25+import { TotpService } from "../../bw/services/totp.service"
26+import { EncryptServiceImplementation } from "../../bw/services/cryptography/encrypt.service.implementation"
25
27
26function sanitize(obj) {
28function sanitize(obj) {
27 return JSON.parse(JSON.stringify(obj));
29 return JSON.parse(JSON.stringify(obj));
@@ -73,7 +75,7 @@ export function getServices() {
73 req.email,
75 req.email,
74 req.masterPasswordHash,
76 req.masterPasswordHash,
75 req.captchaResponse,
77 req.captchaResponse,
76− new TokenRequestTwoFactor(
78+ new TokenTwoFactorRequest(
77 req.twoFactor.provider,
79 req.twoFactor.provider,
78 req.twoFactor.token,
80 req.twoFactor.token,
79 req.twoFactor.remember
81 req.twoFactor.remember
@@ -131,6 +133,7 @@ class MainBackground {
131 new StateFactory(GlobalState, Account)
133 new StateFactory(GlobalState, Account)
132 );
134 );
133 this.stateService = new StateService(
135 this.stateService = new StateService(
136+ this.storageService,
134 this.storageService,
137 this.storageService,
135 this.storageService,
138 this.storageService,
136 this.logService,
139 this.logService,
@@ -161,8 +164,13 @@ class MainBackground {
161 );
164 );
162 this.i18nService = new I18nService("en");
165 this.i18nService = new I18nService("en");
163 this.cryptoFunctionService = new WebCryptoFunctionService(window);
166 this.cryptoFunctionService = new WebCryptoFunctionService(window);
167+ this.encryptService = new EncryptServiceImplementation(
168+ this.cryptoFunctionService,
169+ this.logService
170+ );
164 this.cryptoService = new BrowserCryptoService(
171 this.cryptoService = new BrowserCryptoService(
165 this.cryptoFunctionService,
172 this.cryptoFunctionService,
173+ this.encryptService,
166 this.platformUtilsService,
174 this.platformUtilsService,
167 this.logService,
175 this.logService,
168 this.stateService
176 this.stateService
@@ -206,34 +214,6 @@ class MainBackground {
206 }
214 }
207}
215}
208
216
209−class MemoryStorageService {
210−
211− constructor() {
212− this.storage = {};
213− }
214−
215− async get(key) {
216− return this.storage[key]
217− }
218−
219− async has(key) {
220− return key in this.storage;
221− }
222−
223− async save(key, obj) {
224− if (obj == null) {
225− this.remove(key)
226− return
227− }
228−
229− this.storage[key] = obj
230− }
231−
232− async remove(key) {
233− delete this.storage[key]
234− }
235−}
236−
237class BrowserCryptoService extends CryptoService {
217class BrowserCryptoService extends CryptoService {
238 async retrieveKeyFromStorage(keySuffix) {
218 async retrieveKeyFromStorage(keySuffix) {
239 if (keySuffix === "biometric") {
219 if (keySuffix === "biometric") {
@@ -314,7 +294,7 @@ class BrowserPlatformUtilsService {
314 saveFile(win, blobData, blobOptions, fileName) {
294 saveFile(win, blobData, blobOptions, fileName) {
315 // BrowserApi.downloadFile(win, blobData, blobOptions, fileName);
295 // BrowserApi.downloadFile(win, blobData, blobOptions, fileName);
316 }
296 }
317− getApplicationVersion() {
297+ getApplicationVersionNumber() {
318 // return Promise.resolve(BrowserApi.getApplicationVersion());
298 // return Promise.resolve(BrowserApi.getApplicationVersion());
319 }
299 }
320 supportsWebAuthn(win) {
300 supportsWebAuthn(win) {
backend/BW.purs+37−39
@@ -17,31 +17,31 @@ import Effect (Effect)
17import Effect.Unsafe (unsafePerformEffect)
17import Effect.Unsafe (unsafePerformEffect)
18import Untagged.Union (type (|+|))
18import Untagged.Union (type (|+|))
19
19
20−type TotpService
20+type TotpService =
21− = { getCode :: String -> Promise String
21+ { getCode :: String -> Promise String
22− , getTimeInterval :: String -> Int
22+ , getTimeInterval :: String -> Int
23− }
23+ }
24−
24+
25−type CryptoService
25+type CryptoService =
26− = { makeKey :: Fn4 Password String KDF Int (Promise SymmetricCryptoKey)
26+ { makeKey :: Fn4 Password String KDF KdfConfig (Promise SymmetricCryptoKey)
27− , hashPassword :: Fn3 Password SymmetricCryptoKey (JNullable HashPurpose) (Promise StringHash)
27+ , hashPassword :: Fn3 Password SymmetricCryptoKey (JNullable HashPurpose) (Promise StringHash)
28− , decryptToUtf8 :: Fn2 EncString SymmetricCryptoKey (Promise String)
28+ , decryptToUtf8 :: Fn2 EncString SymmetricCryptoKey (Promise String)
29− , decryptToBytes :: Fn2 EncString SymmetricCryptoKey (Promise ArrayBuffer)
29+ , decryptToBytes :: Fn2 EncString SymmetricCryptoKey (Promise ArrayBuffer)
30− , encrypt :: Fn2 String SymmetricCryptoKey (Promise EncString)
30+ , encrypt :: Fn2 String SymmetricCryptoKey (Promise EncString)
31− , stretchKey :: SymmetricCryptoKey -> Promise SymmetricCryptoKey
31+ , stretchKey :: SymmetricCryptoKey -> Promise SymmetricCryptoKey
32− }
32+ }
33−
33+
34−type ApiService
34+type ApiService =
35− = { postPrelogin :: PreloginRequest -> Promise PreloginResponse
35+ { postPrelogin :: PreloginRequest -> Promise PreloginResponse
36− , getProfile :: Unit -> Promise ProfileResponse
36+ , getProfile :: Unit -> Promise ProfileResponse
37− -- TODO: There can really be more request and response types. Maybe handle this later.
37+ -- TODO: There can really be more request and response types. Maybe handle this later.
38− , postIdentityToken :: PasswordTokenRequest -> Promise (IdentityCaptchaResponse |+| IdentityTwoFactorResponse |+| IdentityTokenResponse)
38+ , postIdentityToken :: PasswordTokenRequest -> Promise (IdentityCaptchaResponse |+| IdentityTwoFactorResponse |+| IdentityTokenResponse)
39− , getSync :: Unit -> Promise SyncResponse
39+ , getSync :: Unit -> Promise SyncResponse
40− , postCipherCreate :: CipherResponse -> Promise CipherResponse
40+ , postCipherCreate :: CipherResponse -> Promise CipherResponse
41− , putCipher :: CipherResponse -> Promise CipherResponse
41+ , putCipher :: CipherResponse -> Promise CipherResponse
42− , deleteCipher :: String -> Promise Unit
42+ , deleteCipher :: String -> Promise Unit
43− , postTwoFactorEmail :: TwoFactorEmailRequest -> Promise Unit
43+ , postTwoFactorEmail :: TwoFactorEmailRequest -> Promise Unit
44− }
44+ }
45
45
46type PasswordGeneration =
46type PasswordGeneration =
47 { generatePassword :: Bridge.PasswordGeneratorConfig -> Promise String
47 { generatePassword :: Bridge.PasswordGeneratorConfig -> Promise String
@@ -55,15 +55,13 @@ cryptoFunctionsTypeSha512 = "sha512" :: CryptoFunctionsType
55
55
56cryptoFunctionsTypeMd5 = "md5" :: CryptoFunctionsType
56cryptoFunctionsTypeMd5 = "md5" :: CryptoFunctionsType
57
57
58−type CryptoFunctionsType
58+type CryptoFunctionsType = String
59− = String
60
59
61−type CryptoFunctions
60+type CryptoFunctions =
62− = { hash :: Fn2 String CryptoFunctionsType (Promise Hash)
61+ { hash :: Fn2 String CryptoFunctionsType (Promise Hash)
63− }
62+ }
64
63
65−newtype Hash
66− = Hash (ArrayBuffer)
64+newtype Hash = Hash (ArrayBuffer)
67
65
68hashToArray :: Hash -> Array Int
66hashToArray :: Hash -> Array Int
69hashToArray (Hash buf) =
67hashToArray (Hash buf) =
@@ -86,12 +84,12 @@ instance EncodeJson Hash where
86instance DecodeJson Hash where
84instance DecodeJson Hash where
87 decodeJson = decodeJson >>> map arrayToHash
85 decodeJson = decodeJson >>> map arrayToHash
88
86
89−type Services
87+type Services =
90− = { crypto :: CryptoService
88+ { crypto :: CryptoService
91− , getApi :: Urls -> JNullable IdentityTokenResponse -> Promise ApiService
89+ , getApi :: Urls -> JNullable IdentityTokenResponse -> Promise ApiService
92− , cryptoFunctions :: CryptoFunctions
90+ , cryptoFunctions :: CryptoFunctions
93− , passwordGeneration :: PasswordGeneration
91+ , passwordGeneration :: PasswordGeneration
94− , totpService :: TotpService
92+ , totpService :: TotpService
95− }
93+ }
96
94
97foreign import getServices :: Effect Services
95foreign import getServices :: Effect Services
backend/BW/Logic.purs+294−248
@@ -3,6 +3,7 @@ module BW.Logic where
3import BW
3import BW
4import BW.Types
4import BW.Types
5import Prelude
5import Prelude
6+
6import Bridge as Bridge
7import Bridge as Bridge
7import Control.Monad.Error.Class (throwError)
8import Control.Monad.Error.Class (throwError)
8import Control.Promise (Promise)
9import Control.Promise (Promise)
@@ -14,6 +15,7 @@ import Data.JNullable as JNullable
14import Data.JOpt (JOpt(..), fromJOpt)
15import Data.JOpt (JOpt(..), fromJOpt)
15import Data.Maybe (Maybe(..), fromMaybe, maybe)
16import Data.Maybe (Maybe(..), fromMaybe, maybe)
16import Data.Newtype (class Newtype, unwrap, wrap)
17import Data.Newtype (class Newtype, unwrap, wrap)
18+import Data.Number.Format as Number
17import Data.String as String
19import Data.String as String
18import Data.SymmetricCryptoKey (SymmetricCryptoKey)
20import Data.SymmetricCryptoKey (SymmetricCryptoKey)
19import Data.SymmetricCryptoKey as SymmetricCryptoKey
21import Data.SymmetricCryptoKey as SymmetricCryptoKey
@@ -25,43 +27,51 @@ import Effect.Aff.Class (class MonadAff, liftAff)
25import Effect.Class (liftEffect)
27import Effect.Class (liftEffect)
26import Effect.Exception (error)
28import Effect.Exception (error)
27import Effect.Exception as Exc
29import Effect.Exception as Exc
30+import Effect.Random (random)
31+import Localstorage as Storage
28import Run (Run)
32import Run (Run)
29import Run.Reader (Reader, askAt)
33import Run.Reader (Reader, askAt)
34+import Storage (DeviceIDKey(..))
30import Type.Prelude (Proxy(..))
35import Type.Prelude (Proxy(..))
31import Untagged.Union (type (|+|))
36import Untagged.Union (type (|+|))
37+import Web.Storage.Storage (Storage)
32
38
33-- | Creates the master key
39-- | Creates the master key
34−makePreloginKey ::
40+makePreloginKey
35− forall r.
41+ :: forall r
36− PreloginResponse ->
42+ . PreloginResponse
37− Email ->
43+ -> Email
38− Password ->
44+ -> Password
39− Run
45+ -> Run
40− ( crypto ::
41− Reader CryptoService
46+ ( crypto :: Reader CryptoService
42− , effect :: Effect
47+ , effect :: Effect
43− , aff :: Aff
48+ , aff :: Aff
44− | r
49+ | r
45− )
50+ )
46− SymmetricCryptoKey
51+ SymmetricCryptoKey
47−makePreloginKey { kdf, kdfIterations } (Email email') password = do
52+makePreloginKey { kdf, kdfIterations, kdfMemory, kdfParallelism } (Email email') password = do
48 crypto <- askAt (Proxy :: _ "crypto")
53 crypto <- askAt (Proxy :: _ "crypto")
49 let
54 let
50 email = (String.trim >>> String.toLower) email'
55 email = (String.trim >>> String.toLower) email'
51− liftPromise $ runFn4 crypto.makeKey password email kdf kdfIterations
56+ liftPromise $ runFn4 crypto.makeKey password email kdf
57+ { iterations: kdfIterations
58+ , memory: kdfMemory
59+ , parallelism: kdfParallelism
60+ }
52
61
53−makeDecryptionKey ::
62+makeDecryptionKey
54− forall r.
63+ :: forall r
64+ .
55 -- | Matser key (prelogin key)
65 -- | Matser key (prelogin key)
56− SymmetricCryptoKey ->
66+ SymmetricCryptoKey
57− EncryptedString ->
67+ -> EncryptedString
58− Run
68+ -> Run
59− ( crypto :: Reader CryptoService
69+ ( crypto :: Reader CryptoService
60− , effect :: Effect
70+ , effect :: Effect
61− , aff :: Aff
71+ , aff :: Aff
62− | r
72+ | r
63− )
73+ )
64− SymmetricCryptoKey
74+ SymmetricCryptoKey
65makeDecryptionKey masterKey str = do
75makeDecryptionKey masterKey str = do
66 crypto <- askAt (Proxy :: _ "crypto")
76 crypto <- askAt (Proxy :: _ "crypto")
67 let
77 let
@@ -78,28 +88,32 @@ makeDecryptionKey masterKey str = do
78 liftEffect $ Exc.throw $ "Unsupported key encryption type: " <> show encType
88 liftEffect $ Exc.throw $ "Unsupported key encryption type: " <> show encType
79 pure $ SymmetricCryptoKey.fromArrayBuffer key
89 pure $ SymmetricCryptoKey.fromArrayBuffer key
80
90
81−getLogInRequestToken ::
91+getLogInRequestToken
82− forall r.
92+ :: forall r
83− { prelogin :: PreloginResponse
93+ . { prelogin :: PreloginResponse
84− , email :: Email
94+ , email :: Email
85− , password :: Password
95+ , password :: Password
86− , captchaResponse :: Maybe String
96+ , captchaResponse :: Maybe String
87− , secondFactor :: Bridge.Cmd_Login_secondFactor_Maybe
97+ , secondFactor :: Bridge.Cmd_Login_secondFactor_Maybe
88− } ->
98+ }
89− Run
99+ -> Run
90− ( api :: Reader ApiService
100+ ( api :: Reader ApiService
91− , crypto :: Reader CryptoService
101+ , crypto :: Reader CryptoService
92− , effect :: Effect
102+ , effect :: Effect
93− , aff :: Aff
103+ , aff :: Aff
104+ , storage :: Reader Storage
94− | r
105+ | r
95− )
106+ )
96− (IdentityCaptchaResponse |+| IdentityTwoFactorResponse |+| IdentityTokenResponse)
107+ (IdentityCaptchaResponse |+| IdentityTwoFactorResponse |+| IdentityTokenResponse)
97−getLogInRequestToken { prelogin
108+getLogInRequestToken
109+ { prelogin
98−, email
110+ , email
99−, password
111+ , password
100−, captchaResponse
112+ , captchaResponse
101−, secondFactor: Bridge.Cmd_Login_secondFactor_Maybe secondFactor
113+ , secondFactor: Bridge.Cmd_Login_secondFactor_Maybe secondFactor
102−} = do
114+ } = do
115+ key <- makePreloginKey prelogin email password
116+ crypto <- askAt (Proxy :: _ "crypto")
103 let
117 let
104 twoFactor =
118 twoFactor =
105 maybe
119 maybe
@@ -111,7 +125,11 @@ getLogInRequestToken { prelogin
111 x { provider = bridgeToSecondFactorType provider }
125 x { provider = bridgeToSecondFactorType provider }
112 )
126 )
113 secondFactor
127 secondFactor
128+ _localHashedPassword <-
129+ liftPromise
130+ $ runFn3 crypto.hashPassword password key (nullify hashPurposeLocalAuthorization)
114− StringHash hashedPassword <- bwPasswordStringHash prelogin email password
131+ StringHash hashedPassword <- liftPromise $ runFn3 crypto.hashPassword password key jnull
132+ deviceId <- getDeviceID
115 api :: ApiService <- askAt (Proxy :: _ "api")
133 api :: ApiService <- askAt (Proxy :: _ "api")
116 liftPromise
134 liftPromise
117 $ api.postIdentityToken
135 $ api.postIdentityToken
@@ -122,23 +140,23 @@ getLogInRequestToken { prelogin
122 , device:
140 , device:
123 { type: deviceTypeUnknownBrowser
141 { type: deviceTypeUnknownBrowser
124 , name: "Ubuntu Touch"
142 , name: "Ubuntu Touch"
125− , identifier: "42"
143+ , identifier: deviceId
126 , pushToken: jnull
144 , pushToken: jnull
127 }
145 }
128 }
146 }
129
147
130−bwPasswordStringHash ::
148+bwPasswordStringHash
131− forall r.
149+ :: forall r
132− PreloginResponse ->
150+ . PreloginResponse
133− Email ->
151+ -> Email
134− Password ->
152+ -> Password
135− Run
153+ -> Run
136− ( crypto :: Reader CryptoService
154+ ( crypto :: Reader CryptoService
137− , effect :: Effect
155+ , effect :: Effect
138− , aff :: Aff
156+ , aff :: Aff
139− | r
157+ | r
140− )
158+ )
141− StringHash
159+ StringHash
142bwPasswordStringHash prelogin email password = do
160bwPasswordStringHash prelogin email password = do
143 key <- makePreloginKey prelogin email password
161 key <- makePreloginKey prelogin email password
144 crypto <- askAt (Proxy :: _ "crypto")
162 crypto <- askAt (Proxy :: _ "crypto")
@@ -147,47 +165,47 @@ bwPasswordStringHash prelogin email password = do
147 $ runFn3 crypto.hashPassword password key (nullify hashPurposeLocalAuthorization)
165 $ runFn3 crypto.hashPassword password key (nullify hashPurposeLocalAuthorization)
148 liftPromise $ runFn3 crypto.hashPassword password key jnull
166 liftPromise $ runFn3 crypto.hashPassword password key jnull
149
167
150−hashPassword ::
168+hashPassword
151− forall r.
169+ :: forall r
152− Password ->
170+ . Password
153− Run
171+ -> Run
154− ( cryptoFunctions :: Reader CryptoFunctions
172+ ( cryptoFunctions :: Reader CryptoFunctions
155− , aff :: Aff
173+ , aff :: Aff
156− , effect :: Effect
174+ , effect :: Effect
157− | r
175+ | r
158− )
176+ )
159− Hash
177+ Hash
160hashPassword (Password password) = do
178hashPassword (Password password) = do
161 cryptoFunctions <- askAt (Proxy :: _ "cryptoFunctions")
179 cryptoFunctions <- askAt (Proxy :: _ "cryptoFunctions")
162 liftPromise $ runFn2 cryptoFunctions.hash password cryptoFunctionsTypeSha512
180 liftPromise $ runFn2 cryptoFunctions.hash password cryptoFunctionsTypeSha512
163
181
164−decrypt ::
182+decrypt
165− forall r.
183+ :: forall r
166− EncryptedString ->
184+ . EncryptedString
167− Run
185+ -> Run
168− ( key :: Reader SymmetricCryptoKey
186+ ( key :: Reader SymmetricCryptoKey
169− , crypto :: Reader CryptoService
187+ , crypto :: Reader CryptoService
170− , aff :: Aff
188+ , aff :: Aff
171− , effect :: Effect
189+ , effect :: Effect
172− | r
190+ | r
173− )
191+ )
174− String
192+ String
175decrypt input = do
193decrypt input = do
176 crypto <- askAt (Proxy :: _ "crypto")
194 crypto <- askAt (Proxy :: _ "crypto")
177 key <- askAt (Proxy :: _ "key")
195 key <- askAt (Proxy :: _ "key")
178 liftPromise $ runFn2 crypto.decryptToUtf8 (EncString.fromString input) key
196 liftPromise $ runFn2 crypto.decryptToUtf8 (EncString.fromString input) key
179
197
180−encrypt ::
198+encrypt
181− forall r.
199+ :: forall r
182− String ->
200+ . String
183− Run
201+ -> Run
184− ( key :: Reader SymmetricCryptoKey
202+ ( key :: Reader SymmetricCryptoKey
185− , crypto :: Reader CryptoService
203+ , crypto :: Reader CryptoService
186− , aff :: Aff
204+ , aff :: Aff
187− , effect :: Effect
205+ , effect :: Effect
188− | r
206+ | r
189− )
207+ )
190− EncryptedString
208+ EncryptedString
191encrypt input = do
209encrypt input = do
192 crypto <- askAt (Proxy :: _ "crypto")
210 crypto <- askAt (Proxy :: _ "crypto")
193 key <- askAt (Proxy :: _ "key")
211 key <- askAt (Proxy :: _ "key")
@@ -196,17 +214,17 @@ encrypt input = do
196liftPromise :: forall m a. MonadAff m => Promise a -> m a
214liftPromise :: forall m a. MonadAff m => Promise a -> m a
197liftPromise = liftAff <<< Promise.toAff
215liftPromise = liftAff <<< Promise.toAff
198
216
199−encodeCipher ::
217+encodeCipher
200− forall r.
218+ :: forall r
201− Bridge.FullCipher ->
219+ . Bridge.FullCipher
202− Run
220+ -> Run
203− ( key :: Reader SymmetricCryptoKey
221+ ( key :: Reader SymmetricCryptoKey
204− , crypto :: Reader CryptoService
222+ , crypto :: Reader CryptoService
205− , aff :: Aff
223+ , aff :: Aff
206− , effect :: Effect
224+ , effect :: Effect
207− | r
225+ | r
208− )
226+ )
209− CipherResponse
227+ CipherResponse
210encodeCipher
228encodeCipher
211 (Bridge.FullCipher { name, cipher, id, favorite, reprompt, collectionIds }) = do
229 (Bridge.FullCipher { name, cipher, id, favorite, reprompt, collectionIds }) = do
212 let
230 let
@@ -222,14 +240,14 @@ encodeCipher
222 pure
240 pure
223 x
241 x
224 { card =
242 { card =
225− nullify
243+ nullify
226− { cardholderName
244+ { cardholderName
227− , brand
245+ , brand
228− , number
246+ , number
229− , expMonth
247+ , expMonth
230− , expYear
248+ , expYear
231− , code
249+ , code
232− }
250+ }
233 , type = cipherTypeCard
251 , type = cipherTypeCard
234 }
252 }
235 Bridge.IdentityCipher (Bridge.Cipher_IdentityCipher identity) -> do
253 Bridge.IdentityCipher (Bridge.Cipher_IdentityCipher identity) -> do
@@ -254,26 +272,26 @@ encodeCipher
254 pure
272 pure
255 x
273 x
256 { identity =
274 { identity =
257− nullify
275+ nullify
258− { address1
276+ { address1
259− , address2
277+ , address2
260− , address3
278+ , address3
261− , city
279+ , city
262− , company
280+ , company
263− , country
281+ , country
264− , email
282+ , email
265− , firstName
283+ , firstName
266− , lastName
284+ , lastName
267− , licenseNumber
285+ , licenseNumber
268− , middleName
286+ , middleName
269− , passportNumber
287+ , passportNumber
270− , phone
288+ , phone
271− , postalCode
289+ , postalCode
272− , ssn
290+ , ssn
273− , state
291+ , state
274− , title
292+ , title
275− , username
293+ , username
276− }
294+ }
277 , type = cipherTypeIdentity
295 , type = cipherTypeIdentity
278 }
296 }
279 Bridge.LoginCipher (Bridge.Cipher_LoginCipher login) -> do
297 Bridge.LoginCipher (Bridge.Cipher_LoginCipher login) -> do
@@ -281,7 +299,7 @@ encodeCipher
281 uris <-
299 uris <-
282 traverse
300 traverse
283 ( \uri -> do
301 ( \uri -> do
284− uriEnc <- encrypt uri
302+ uriEnc <- nullify <$> encrypt uri
285 pure { uri: uriEnc, match: jnull }
303 pure { uri: uriEnc, match: jnull }
286 )
304 )
287 (unwrap login.uris)
305 (unwrap login.uris)
@@ -290,14 +308,14 @@ encodeCipher
290 pure
308 pure
291 x
309 x
292 { login =
310 { login =
293− nullify
311+ nullify
294− { password
312+ { password
295− , uris: JOpt $ opt uris
313+ , uris: JOpt $ opt uris
296− , username
314+ , username
297− , passwordRevisionDate: jnull
315+ , passwordRevisionDate: jnull
298− , totp: totp
316+ , totp: totp
299− , autofillOnPageLoad: JOpt undefined
317+ , autofillOnPageLoad: JOpt undefined
300− }
318+ }
301 , type = cipherTypeLogin
319 , type = cipherTypeLogin
302 }
320 }
303 Bridge.NoteCipher note -> do
321 Bridge.NoteCipher note -> do
@@ -332,100 +350,110 @@ encodeCipher
332 , reprompt
350 , reprompt
333 }
351 }
334
352
335−decodeCipher ::
353+-- | Check if the cipher is supported by Warden.
354+supportedCipher :: CipherResponse -> Boolean
355+-- We do not support organizations since that requires managing a separate set of
356+-- encryption keys
357+supportedCipher { organizationId } | Just _ <- JNullable.toMaybe organizationId = false
358+supportedCipher _ = true
359+
360+decodeCipher
336− forall r.
361+ :: forall r
337− CipherResponse ->
362+ . CipherResponse
338− Run
363+ -> Run
339− ( key :: Reader SymmetricCryptoKey
364+ ( key :: Reader SymmetricCryptoKey
340− , crypto :: Reader CryptoService
365+ , crypto :: Reader CryptoService
341− , aff :: Aff
366+ , aff :: Aff
342− , effect :: Effect
367+ , effect :: Effect
343− | r
368+ | r
344− )
369+ )
345− Bridge.FullCipher
370+ (Maybe Bridge.FullCipher)
371+decodeCipher cipher | not (supportedCipher cipher) =
372+ pure $ Nothing
346decodeCipher cipher = do
373decodeCipher cipher = do
347 name <- decrypt cipher.name
374 name <- decrypt cipher.name
348 cipherType <- case cipher.type of
375 cipherType <- case cipher.type of
349 n
376 n
350 | cipherTypeSecureNote == n -> do
377 | cipherTypeSecureNote == n -> do
351− note <- fromJNullable "" <$> (traverse decrypt cipher.notes)
378+ note <- fromJNullable "" <$> (traverse decrypt cipher.notes)
352− pure $ Bridge.NoteCipher note
379+ pure $ Bridge.NoteCipher note
353 n
380 n
354 | cipherTypeLogin == n -> do
381 | cipherTypeLogin == n -> do
355− case JNullable.toMaybe cipher.login of
382+ case JNullable.toMaybe cipher.login of
356− Nothing -> liftEffect $ throwError $ error "Login data is missing"
383+ Nothing -> liftEffect $ throwError $ error "Login data is missing"
357− Just login -> do
384+ Just login -> do
358− username <- decryptNullable login.username
385+ username <- decryptNullable login.username
359− password <- decryptNullable login.password
386+ password <- decryptNullable login.password
360− totp <- decryptNullable login.totp
387+ totp <- decryptNullable login.totp
388+ uris <- fromJOpt [] <$>
361− uris <- fromJOpt [] <$> ((traverse >>> traverse) (_.uri >>> decrypt) login.uris)
389+ ((traverse >>> traverse) (_.uri >>> JNullable.toMaybe >>> maybe (pure "") decrypt) login.uris)
362− pure $ Bridge.LoginCipher
390+ pure $ Bridge.LoginCipher
363− $ Bridge.Cipher_LoginCipher
391+ $ Bridge.Cipher_LoginCipher
364− { username
392+ { username
365− , password
393+ , password
366− , uris: wrap uris
394+ , uris: wrap uris
367− , totp
395+ , totp
368− }
396+ }
369 n
397 n
370 | cipherTypeCard == n -> do
398 | cipherTypeCard == n -> do
371− case JNullable.toMaybe cipher.card of
399+ case JNullable.toMaybe cipher.card of
372− Nothing -> liftEffect $ throwError $ error "Card data is missing"
400+ Nothing -> liftEffect $ throwError $ error "Card data is missing"
373− Just card -> do
401+ Just card -> do
374− cardholderName <- decryptNullable card.cardholderName
402+ cardholderName <- decryptNullable card.cardholderName
375− number <- decryptNullable card.number
403+ number <- decryptNullable card.number
376− code <- decryptNullable card.code
404+ code <- decryptNullable card.code
377− brand <- decryptNullable card.brand
405+ brand <- decryptNullable card.brand
378− expMonth <- decryptNullable card.expMonth
406+ expMonth <- decryptNullable card.expMonth
379− expYear <- decryptNullable card.expYear
407+ expYear <- decryptNullable card.expYear
380− pure $ Bridge.CardCipher
408+ pure $ Bridge.CardCipher
381− $ Bridge.Cipher_CardCipher
409+ $ Bridge.Cipher_CardCipher
382− { brand, cardholderName, code, expMonth, expYear, number }
410+ { brand, cardholderName, code, expMonth, expYear, number }
383 n
411 n
384 | cipherTypeIdentity == n -> do
412 | cipherTypeIdentity == n -> do
385− case JNullable.toMaybe cipher.identity of
413+ case JNullable.toMaybe cipher.identity of
386− Nothing -> liftEffect $ throwError $ error "Identity data is missing"
414+ Nothing -> liftEffect $ throwError $ error "Identity data is missing"
387− Just identity -> do
415+ Just identity -> do
388− firstName <- decryptNullable identity.firstName
416+ firstName <- decryptNullable identity.firstName
389− middleName <- decryptNullable identity.middleName
417+ middleName <- decryptNullable identity.middleName
390− lastName <- decryptNullable identity.lastName
418+ lastName <- decryptNullable identity.lastName
391− address1 <- decryptNullable identity.address1
419+ address1 <- decryptNullable identity.address1
392− address2 <- decryptNullable identity.address2
420+ address2 <- decryptNullable identity.address2
393− address3 <- decryptNullable identity.address3
421+ address3 <- decryptNullable identity.address3
394− city <- decryptNullable identity.city
422+ city <- decryptNullable identity.city
395− company <- decryptNullable identity.company
423+ company <- decryptNullable identity.company
396− country <- decryptNullable identity.country
424+ country <- decryptNullable identity.country
397− email <- decryptNullable identity.email
425+ email <- decryptNullable identity.email
398− licenseNumber <- decryptNullable identity.licenseNumber
426+ licenseNumber <- decryptNullable identity.licenseNumber
399− passportNumber <- decryptNullable identity.passportNumber
427+ passportNumber <- decryptNullable identity.passportNumber
400− phone <- decryptNullable identity.phone
428+ phone <- decryptNullable identity.phone
401− postalCode <- decryptNullable identity.postalCode
429+ postalCode <- decryptNullable identity.postalCode
402− ssn <- decryptNullable identity.ssn
430+ ssn <- decryptNullable identity.ssn
403− state <- decryptNullable identity.state
431+ state <- decryptNullable identity.state
404− title <- decryptNullable identity.title
432+ title <- decryptNullable identity.title
405− username <- decryptNullable identity.username
433+ username <- decryptNullable identity.username
406− pure $ Bridge.IdentityCipher
434+ pure $ Bridge.IdentityCipher
407− $ wrap
435+ $ wrap
408− { firstName
436+ { firstName
409− , middleName
437+ , middleName
410− , lastName
438+ , lastName
411− , address1
439+ , address1
412− , address2
440+ , address2
413− , address3
441+ , address3
414− , city
442+ , city
415− , company
443+ , company
416− , country
444+ , country
417− , email
445+ , email
418− , licenseNumber
446+ , licenseNumber
419− , passportNumber
447+ , passportNumber
420− , phone
448+ , phone
421− , postalCode
449+ , postalCode
422− , ssn
450+ , ssn
423− , state
451+ , state
424− , title
452+ , title
425− , username
453+ , username
426− }
454+ }
427 n -> liftEffect $ throwError $ error $ "Unsupported cipher type: " <> show n
455 n -> liftEffect $ throwError $ error $ "Unsupported cipher type: " <> show n
428− pure
456+ pure $ Just
429 $ wrap
457 $ wrap
430 { cipher: cipherType
458 { cipher: cipherType
431 , name
459 , name
@@ -435,32 +463,50 @@ decodeCipher cipher = do
435 , collectionIds: wrap <<< fromJNullable [] $ cipher.collectionIds
463 , collectionIds: wrap <<< fromJNullable [] $ cipher.collectionIds
436 }
464 }
437
465
438−decryptNullable ::
466+decryptNullable
439− forall x r.
467+ :: forall x r
440− Newtype x (Maybe String) =>
468+ . Newtype x (Maybe String)
441− JNullable EncryptedString ->
469+ => JNullable EncryptedString
442− Run
470+ -> Run
443− ( key :: Reader SymmetricCryptoKey
471+ ( key :: Reader SymmetricCryptoKey
444− , crypto :: Reader CryptoService
472+ , crypto :: Reader CryptoService
445− , aff :: Aff
473+ , aff :: Aff
446− , effect :: Effect
474+ , effect :: Effect
447− | r
475+ | r
448− )
476+ )
449− x
477+ x
450decryptNullable x = wrap <<< fromJNullable Nothing <<< map Just <$> (traverse decrypt x)
478decryptNullable x = wrap <<< fromJNullable Nothing <<< map Just <$> (traverse decrypt x)
451
479
452−encryptNullable ::
480+encryptNullable
453− forall x r.
481+ :: forall x r
454− Newtype x (Maybe String) =>
482+ . Newtype x (Maybe String)
455− x ->
483+ => x
456− Run
484+ -> Run
457− ( key :: Reader SymmetricCryptoKey
485+ ( key :: Reader SymmetricCryptoKey
458− , crypto :: Reader CryptoService
486+ , crypto :: Reader CryptoService
459− , aff :: Aff
487+ , aff :: Aff
460− , effect :: Effect
488+ , effect :: Effect
461− | r
489+ | r
462− )
490+ )
463− (JNullable EncryptedString)
491+ (JNullable EncryptedString)
464encryptNullable x = case unwrap x of
492encryptNullable x = case unwrap x of
465 Nothing -> pure jnull
493 Nothing -> pure jnull
466 Just y -> nullify <$> encrypt y
494 Just y -> nullify <$> encrypt y
495+
496+getDeviceID ::
497+ forall r.
498+ Run
499+ ( effect :: Effect
500+ , storage :: Reader Storage
501+ | r
502+ )
503+ String
504+getDeviceID = do
505+ storage <- askAt (Proxy :: _ "storage")
506+ maybeId <- liftEffect $ Storage.get storage DeviceIDKey
507+ case maybeId of
508+ Just id -> pure id
509+ Nothing -> do
510+ id <- map Number.toString $ liftEffect $ random
511+ liftEffect $ Storage.store storage DeviceIDKey id
512+ pure id
backend/BW/Types.purs+377−390
@@ -10,6 +10,7 @@ import Data.Int as Int
10import Data.JNullable (JNullable)
10import Data.JNullable (JNullable)
11import Data.JOpt (JOpt)
11import Data.JOpt (JOpt)
12import Data.Maybe (Maybe(..))
12import Data.Maybe (Maybe(..))
13+import Data.Nullable (Nullable)
13import Data.ShowableJson (ShowableJson)
14import Data.ShowableJson (ShowableJson)
14import Data.Timestamp (Timestamp)
15import Data.Timestamp (Timestamp)
15import Data.Traversable (for)
16import Data.Traversable (for)
@@ -21,8 +22,7 @@ import Untagged.TypeCheck (class HasRuntimeType)
21import Untagged.Union (type (|+|))
22import Untagged.Union (type (|+|))
22import Untagged.Union as Union
23import Untagged.Union as Union
23
24
24−newtype EncryptedString
25+newtype EncryptedString = EncryptedString String
25− = EncryptedString String
26
26
27derive newtype instance Show EncryptedString
27derive newtype instance Show EncryptedString
28derive newtype instance Ord EncryptedString
28derive newtype instance Ord EncryptedString
@@ -31,78 +31,86 @@ derive newtype instance EncodeJson EncryptedString
31derive newtype instance DecodeJson EncryptedString
31derive newtype instance DecodeJson EncryptedString
32
32
33kdfPBKDF2_SHA256 = 0 :: KDF
33kdfPBKDF2_SHA256 = 0 :: KDF
34+kdfArgon2id = 1 :: KDF
34
35
35−type KDF
36+type KDF = Int
36− = Int
37+
37−
38−type PreloginResponse
38+type PreloginResponse =
39− = { kdf :: KDF
39+ { kdf :: KDF
40− , kdfIterations :: Int
40+ , kdfIterations :: Int
41+ , kdfMemory :: JNullable Int
42+ , kdfParallelism :: JNullable Int
43+ }
44+
45+type KdfConfig =
46+ { iterations :: Int
47+ , memory :: JNullable Int
48+ , parallelism :: JNullable Int
41− }
49+ }
42−
50+
43−type PreloginRequest
51+type PreloginRequest =
44− = { email :: Email
52+ { email :: Email
45− }
53+ }
46−
54+
47−type ProfileResponse
55+type ProfileResponse =
48− = { id :: String
56+ { id :: String
49− , name :: JNullable String
57+ , name :: JNullable String
50− , email :: String
58+ , email :: String
51− , emailVerified :: Boolean
59+ , emailVerified :: Boolean
52− , masterPasswordHint :: JNullable String
60+ , masterPasswordHint :: JNullable String
53− , premiumPersonally :: Boolean
61+ -- , premiumPersonally :: Boolean
54− -- , premiumFromOrganization :: Boolean
62+ -- , premiumFromOrganization :: Boolean
55− , culture :: JNullable String
63+ , culture :: JNullable String
56− , twoFactorEnabled :: Boolean
64+ , twoFactorEnabled :: Boolean
57− , key :: EncryptedString
65+ , key :: EncryptedString
58− , privateKey :: EncryptedString
66+ , privateKey :: EncryptedString
59− , securityStamp :: JNullable String
67+ , securityStamp :: JNullable String
60− , forcePasswordReset :: Boolean
68+ , forcePasswordReset :: Boolean
61− , usesKeyConnector :: Boolean
69+ , usesKeyConnector :: Boolean
62− , organizations :: Array ProfileOrganizationResponse
70+ -- , organizations :: Array ProfileOrganizationResponse
63− , providers :: Array ProfileProviderResponse
71+ , providers :: Array ProfileProviderResponse
64− , providerOrganizations :: Array ProfileProviderOrganizationResponse
72+ , providerOrganizations :: Array ProfileProviderOrganizationResponse
65− }
73+ }
66−
74+
67−type ProfileOrganizationResponse
75+type ProfileOrganizationResponse =
68− = { id :: String
76+ { id :: String
69− , name :: JNullable String
77+ , name :: JNullable String
70− , usePolicies :: JNullable Boolean
78+ , usePolicies :: JNullable Boolean
71− , useGroups :: JNullable Boolean
79+ , useGroups :: JNullable Boolean
72− , useDirectory :: JNullable Boolean
80+ , useDirectory :: JNullable Boolean
73− , useEvents :: JNullable Boolean
81+ , useEvents :: JNullable Boolean
74− , useTotp :: JNullable Boolean
82+ , useTotp :: JNullable Boolean
75− , use2fa :: JNullable Boolean
83+ , use2fa :: JNullable Boolean
76− , useApi :: JNullable Boolean
84+ , useApi :: JNullable Boolean
77− , useSso :: JNullable Boolean
85+ , useSso :: JNullable Boolean
78− , useKeyConnector :: JNullable Boolean
86+ , useKeyConnector :: JNullable Boolean
79− , useResetPassword :: JNullable Boolean
87+ , useResetPassword :: JNullable Boolean
80− , selfHost :: JNullable Boolean
88+ , selfHost :: JNullable Boolean
81− , usersGetPremium :: JNullable Boolean
89+ , usersGetPremium :: JNullable Boolean
82− , seats :: JNullable Int
90+ , seats :: JNullable Int
83− , maxCollections :: JNullable Int
91+ , maxCollections :: JNullable Int
84− , maxStorageGb :: JNullable Int
92+ , maxStorageGb :: JNullable Int
85− , key :: JNullable String
93+ , key :: JNullable String
86− , hasPublicAndPrivateKeys :: JNullable Boolean
94+ , hasPublicAndPrivateKeys :: JNullable Boolean
87− , status :: JNullable OrganizationUserStatusType
95+ , status :: JNullable OrganizationUserStatusType
88− , type :: JNullable OrganizationUserType
96+ , type :: JNullable OrganizationUserType
89− , enabled :: JNullable Boolean
97+ , enabled :: JNullable Boolean
90− , ssoBound :: JNullable Boolean
98+ , ssoBound :: JNullable Boolean
91− , identifier :: JNullable String
99+ , identifier :: JNullable String
92− , permissions :: JNullable PermissionsApi
100+ , permissions :: JNullable PermissionsApi
93− , resetPasswordEnrolled :: JNullable Boolean
101+ , resetPasswordEnrolled :: JNullable Boolean
94− , userId :: JNullable String
102+ , userId :: JNullable String
95− , providerId :: JNullable String
103+ , providerId :: JNullable String
96− , providerName :: JNullable String
104+ , providerName :: JNullable String
97− , familySponsorshipFriendlyName :: JNullable String
105+ , familySponsorshipFriendlyName :: JNullable String
98− , familySponsorshipAvailable :: JNullable Boolean
106+ , familySponsorshipAvailable :: JNullable Boolean
99− , planProductType :: JNullable ProductType
107+ , planProductType :: JNullable ProductType
100− , keyConnectorEnabled :: JNullable Boolean
108+ , keyConnectorEnabled :: JNullable Boolean
101− , keyConnectorUrl :: JNullable String
109+ , keyConnectorUrl :: JNullable String
102− , familySponsorshipLastSyncDate :: JNullable Timestamp
110+ , familySponsorshipLastSyncDate :: JNullable Timestamp
103− , familySponsorshipValidUntil :: JNullable Timestamp
111+ , familySponsorshipValidUntil :: JNullable Timestamp
104− , familySponsorshipToDelete :: JNullable Boolean
112+ , familySponsorshipToDelete :: JNullable Boolean
105− }
113+ }
106
114
107organizationUserStatusTypeInvited = 0 :: OrganizationUserStatusType
115organizationUserStatusTypeInvited = 0 :: OrganizationUserStatusType
108
116
@@ -110,8 +118,7 @@ organizationUserStatusTypeAccepted = 0 :: OrganizationUserStatusType
110
118
111organizationUserStatusTypeConfirmed = 0 :: OrganizationUserStatusType
119organizationUserStatusTypeConfirmed = 0 :: OrganizationUserStatusType
112
120
113−type OrganizationUserStatusType
121+type OrganizationUserStatusType = Int
114− = Int
115
122
116organizationUserTypeOwner = 0 :: OrganizationUserType
123organizationUserTypeOwner = 0 :: OrganizationUserType
117
124
@@ -123,27 +130,26 @@ organizationUserTypeManager = 3 :: OrganizationUserType
123
130
124organizationUserTypeCustom = 4 :: OrganizationUserType
131organizationUserTypeCustom = 4 :: OrganizationUserType
125
132
126−type OrganizationUserType
133+type OrganizationUserType = Int
127− = Int
134+
128−
129−type PermissionsApi
135+type PermissionsApi =
130− = { accessEventLogs :: Boolean
136+ { accessEventLogs :: Boolean
131− , accessImportExport :: Boolean
137+ , accessImportExport :: Boolean
132− , accessReports :: Boolean
138+ , accessReports :: Boolean
133− , manageAllCollections :: Boolean
139+ , manageAllCollections :: Boolean
134− , createNewCollections :: Boolean
140+ , createNewCollections :: Boolean
135− , editAnyCollection :: Boolean
141+ , editAnyCollection :: Boolean
136− , deleteAnyCollection :: Boolean
142+ , deleteAnyCollection :: Boolean
137− , manageAssignedCollections :: Boolean
143+ , manageAssignedCollections :: Boolean
138− , editAssignedCollections :: Boolean
144+ , editAssignedCollections :: Boolean
139− , deleteAssignedCollections :: Boolean
145+ , deleteAssignedCollections :: Boolean
140− , manageCiphers :: Boolean
146+ , manageCiphers :: Boolean
141− , manageGroups :: Boolean
147+ , manageGroups :: Boolean
142− , manageSso :: Boolean
148+ , manageSso :: Boolean
143− , managePolicies :: Boolean
149+ , managePolicies :: Boolean
144− , manageUsers :: Boolean
150+ , manageUsers :: Boolean
145− , manageResetPassword :: Boolean
151+ , manageResetPassword :: Boolean
146− }
152+ }
147
153
148productTypeFree = 0 :: ProductType
154productTypeFree = 0 :: ProductType
149
155
@@ -153,20 +159,19 @@ productTypeTeams = 2 :: ProductType
153
159
154productTypeEnterprise = 3 :: ProductType
160productTypeEnterprise = 3 :: ProductType
155
161
156−type ProductType
162+type ProductType = Int
157− = Int
163+
158−
159−type ProfileProviderResponse
164+type ProfileProviderResponse =
160− = { id :: String
165+ { id :: String
161− , name :: JNullable String
166+ , name :: JNullable String
162− , key :: JNullable String
167+ , key :: JNullable String
163− , status :: JNullable ProviderUserStatusType
168+ , status :: JNullable ProviderUserStatusType
164− , type :: JNullable ProviderUserType
169+ , type :: JNullable ProviderUserType
165− , enabled :: Boolean
170+ , enabled :: Boolean
166− , permissions :: PermissionsApi
171+ , permissions :: PermissionsApi
167− , userId :: JNullable String
172+ , userId :: JNullable String
168− , useEvents :: Boolean
173+ , useEvents :: Boolean
169− }
174+ }
170
175
171providerUserStatusTypeInvited = 0 :: ProviderUserStatusType
176providerUserStatusTypeInvited = 0 :: ProviderUserStatusType
172
177
@@ -174,81 +179,79 @@ providerUserStatusTypeAccepted = 1 :: ProviderUserStatusType
174
179
175providerUserStatusTypeConfirmed = 2 :: ProviderUserStatusType
180providerUserStatusTypeConfirmed = 2 :: ProviderUserStatusType
176
181
177−type ProviderUserStatusType
182+type ProviderUserStatusType = Int
178− = Int
179
183
180providerUserTypeProviderAdmin = 0 :: ProviderUserType
184providerUserTypeProviderAdmin = 0 :: ProviderUserType
181
185
182providerUserTypeServiceUser = 1 :: ProviderUserType
186providerUserTypeServiceUser = 1 :: ProviderUserType
183
187
184−type ProviderUserType
188+type ProviderUserType = Int
185− = Int
189+
186−
187−type ProfileProviderOrganizationResponse
190+type ProfileProviderOrganizationResponse =
188− = { id :: String
191+ { id :: String
189− , name :: JNullable String
192+ , name :: JNullable String
190− , usePolicies :: Boolean
193+ , usePolicies :: Boolean
191− , useGroups :: Boolean
194+ , useGroups :: Boolean
192− , useDirectory :: Boolean
195+ , useDirectory :: Boolean
193− , useEvents :: Boolean
196+ , useEvents :: Boolean
194− , useTotp :: Boolean
197+ , useTotp :: Boolean
195− , use2fa :: Boolean
198+ , use2fa :: Boolean
196− , useApi :: Boolean
199+ , useApi :: Boolean
197− , useSso :: Boolean
200+ , useSso :: Boolean
198− , useKeyConnector :: Boolean
201+ , useKeyConnector :: Boolean
199− , useResetPassword :: Boolean
202+ , useResetPassword :: Boolean
200− , selfHost :: Boolean
203+ , selfHost :: Boolean
201− , usersGetPremium :: Boolean
204+ , usersGetPremium :: Boolean
202− , seats :: Int
205+ , seats :: Int
203− , maxCollections :: Int
206+ , maxCollections :: Int
204− , maxStorageGb :: JNullable Int
207+ , maxStorageGb :: JNullable Int
205− , key :: JNullable String
208+ , key :: JNullable String
206− , hasPublicAndPrivateKeys :: Boolean
209+ , hasPublicAndPrivateKeys :: Boolean
207− , status :: OrganizationUserStatusType
210+ , status :: OrganizationUserStatusType
208− , type :: OrganizationUserType
211+ , type :: OrganizationUserType
209− , enabled :: Boolean
212+ , enabled :: Boolean
210− , ssoBound :: Boolean
213+ , ssoBound :: Boolean
211− , identifier :: JNullable String
214+ , identifier :: JNullable String
212− , permissions :: PermissionsApi
215+ , permissions :: PermissionsApi
213− , resetPasswordEnrolled :: Boolean
216+ , resetPasswordEnrolled :: Boolean
214− , userId :: JNullable String
217+ , userId :: JNullable String
215− , providerId :: JNullable String
218+ , providerId :: JNullable String
216− , providerName :: JNullable String
219+ , providerName :: JNullable String
217− , familySponsorshipFriendlyName :: JNullable String
220+ , familySponsorshipFriendlyName :: JNullable String
218− , familySponsorshipAvailable :: Boolean
221+ , familySponsorshipAvailable :: Boolean
219− , planProductType :: ProductType
222+ , planProductType :: ProductType
220− , keyConnectorEnabled :: Boolean
223+ , keyConnectorEnabled :: Boolean
221− , keyConnectorUrl :: JNullable String
224+ , keyConnectorUrl :: JNullable String
222− , familySponsorshipLastSyncDate :: JNullable Timestamp
225+ , familySponsorshipLastSyncDate :: JNullable Timestamp
223− , familySponsorshipValidUntil :: JNullable Timestamp
226+ , familySponsorshipValidUntil :: JNullable Timestamp
224− , familySponsorshipToDelete :: JNullable Boolean
227+ , familySponsorshipToDelete :: JNullable Boolean
225− }
228+ }
226−
229+
227−type Urls
230+type Urls =
228− = { base :: JNullable String
231+ { base :: JNullable String
229− , webVault :: JNullable String
232+ , webVault :: JNullable String
230− , api :: JNullable String
233+ , api :: JNullable String
231− , identity :: JNullable String
234+ , identity :: JNullable String
232− , icons :: JNullable String
235+ , icons :: JNullable String
233− , notifications :: JNullable String
236+ , notifications :: JNullable String
234− , events :: JNullable String
237+ , events :: JNullable String
235− , keyConnector :: JNullable String
238+ , keyConnector :: JNullable String
236− }
239+ }
237−
240+
238−type PasswordTokenRequest
241+type PasswordTokenRequest =
239− = { email :: Email
242+ { email :: Email
240− , masterPasswordHash :: String
243+ , masterPasswordHash :: String
241− , captchaResponse :: String
244+ , captchaResponse :: String
242− , twoFactor :: TokenRequestTwoFactor
245+ , twoFactor :: TokenRequestTwoFactor
243− , device :: DeviceRequest
246+ , device :: DeviceRequest
244− }
247+ }
245−
248+
246−type DeviceRequest
249+type DeviceRequest =
247− = { type :: DeviceType
250+ { type :: DeviceType
248− , name :: String
251+ , name :: String
249− , identifier :: String
252+ , identifier :: String
250− , pushToken :: JNullable String
253+ , pushToken :: JNullable String
251− }
254+ }
252
255
253deviceTypeAndroid = 0 :: DeviceType
256deviceTypeAndroid = 0 :: DeviceType
254
257
@@ -292,14 +295,13 @@ deviceTypeVivaldiExtension = 19 :: DeviceType
292
295
293deviceTypeSafariExtension = 20 :: DeviceType
296deviceTypeSafariExtension = 20 :: DeviceType
294
297
295−type DeviceType
298+type DeviceType = Int
296− = Int
297
299
298−type TokenRequestTwoFactor
300+type TokenRequestTwoFactor =
299− = { provider :: TwoFactorProviderType
301+ { provider :: TwoFactorProviderType
300− , token :: String
302+ , token :: String
301− , remember :: Boolean
303+ , remember :: Boolean
302− }
304+ }
303
305
304twoFactorProviderTypeAuthenticator = 0 :: TwoFactorProviderType
306twoFactorProviderTypeAuthenticator = 0 :: TwoFactorProviderType
305
307
@@ -317,12 +319,11 @@ twoFactorProviderTypeOrganizationDuo = 6 :: TwoFactorProviderType
317
319
318twoFactorProviderTypeWebAuthn = 7 :: TwoFactorProviderType
320twoFactorProviderTypeWebAuthn = 7 :: TwoFactorProviderType
319
321
320−type TwoFactorProviderType
322+type TwoFactorProviderType = Int
321− = Int
322
323
323−secondFactorTypeToBridge ::
324+secondFactorTypeToBridge
324− TwoFactorProviderType ->
325+ :: TwoFactorProviderType
325− Maybe Bridge.TwoFactorProviderType
326+ -> Maybe Bridge.TwoFactorProviderType
326secondFactorTypeToBridge x = case x of
327secondFactorTypeToBridge x = case x of
327 n
328 n
328 | n == twoFactorProviderTypeAuthenticator -> Just Bridge.Authenticator
329 | n == twoFactorProviderTypeAuthenticator -> Just Bridge.Authenticator
@@ -352,21 +353,17 @@ bridgeToSecondFactorType Bridge.Remember = twoFactorProviderTypeRemember
352bridgeToSecondFactorType Bridge.OrganizationDuo = twoFactorProviderTypeOrganizationDuo
353bridgeToSecondFactorType Bridge.OrganizationDuo = twoFactorProviderTypeOrganizationDuo
353bridgeToSecondFactorType Bridge.WebAuthn = twoFactorProviderTypeWebAuthn
354bridgeToSecondFactorType Bridge.WebAuthn = twoFactorProviderTypeWebAuthn
354
355
355−newtype Password
356+newtype Password = Password String
356− = Password String
357
357
358hashPurposeServerAuthorization = 1 :: HashPurpose
358hashPurposeServerAuthorization = 1 :: HashPurpose
359
359
360hashPurposeLocalAuthorization = 2 :: HashPurpose
360hashPurposeLocalAuthorization = 2 :: HashPurpose
361
361
362−type HashPurpose
362+type HashPurpose = Int
363− = Int
364
363
365−newtype StringHash
364+newtype StringHash = StringHash String
366− = StringHash String
367
365
368−newtype AccessToken
366+newtype AccessToken = AccessToken String
369− = AccessToken String
370
367
371derive newtype instance Show AccessToken
368derive newtype instance Show AccessToken
372derive newtype instance Eq AccessToken
369derive newtype instance Eq AccessToken
@@ -374,8 +371,7 @@ derive newtype instance Ord AccessToken
374derive newtype instance EncodeJson AccessToken
371derive newtype instance EncodeJson AccessToken
375derive newtype instance DecodeJson AccessToken
372derive newtype instance DecodeJson AccessToken
376
373
377−newtype RefreshToken
374+newtype RefreshToken = RefreshToken String
378− = RefreshToken String
379
375
380derive newtype instance Show RefreshToken
376derive newtype instance Show RefreshToken
381derive newtype instance Eq RefreshToken
377derive newtype instance Eq RefreshToken
@@ -387,21 +383,21 @@ type IdentityCaptchaResponse =
387 { siteKey :: String
383 { siteKey :: String
388 }
384 }
389
385
390−type IdentityTokenResponse
386+type IdentityTokenResponse =
391− = { accessToken :: AccessToken
387+ { accessToken :: AccessToken
392− , expiresIn :: Int
388+ , expiresIn :: Int
393− , refreshToken :: RefreshToken
389+ , refreshToken :: RefreshToken
394− , tokenType :: String
390+ , tokenType :: String
395− , resetMasterPassword :: Boolean
391+ , resetMasterPassword :: Boolean
396− , privateKey :: EncryptedString
392+ , privateKey :: EncryptedString
397− , key :: EncryptedString
393+ , key :: EncryptedString
398− , twoFactorToken :: JNullable String
394+ , twoFactorToken :: JNullable String
399− , kdf :: KDF
395+ , kdf :: KDF
400− , kdfIterations :: Int
396+ , kdfIterations :: Int
401− , forcePasswordReset :: JNullable Boolean
397+ , forcePasswordReset :: JNullable Boolean
402− , apiUseKeyConnector :: JNullable Boolean
398+ , apiUseKeyConnector :: JNullable Boolean
403− , keyConnectorUrl :: JNullable String
399+ , keyConnectorUrl :: JNullable String
404− }
400+ }
405
401
406newtype TwoFactorProviderTypes = TwoFactorProviderTypes (Array (Int |+| String))
402newtype TwoFactorProviderTypes = TwoFactorProviderTypes (Array (Int |+| String))
407
403
@@ -421,59 +417,57 @@ type IdentityTwoFactorResponse =
421 , captchaToken :: String |+| Undefined
417 , captchaToken :: String |+| Undefined
422 }
418 }
423
419
424−newtype Email
420+newtype Email = Email String
425− = Email String
426
421
427−type SyncResponse
422+type SyncResponse =
428− = { profile :: ProfileResponse
423+ { profile :: ProfileResponse
429− , folders :: Array FolderResponse
424+ , folders :: Array FolderResponse
430− , collections :: Array CollectionDetailsResponse
425+ , collections :: Array CollectionDetailsResponse
431− , ciphers :: Array CipherResponse
426+ , ciphers :: Array CipherResponse
432− , domains :: JNullable DomainsResponse
427+ , domains :: JNullable DomainsResponse
433− , policies :: JNullable (Array PolicyResponse)
428+ , policies :: JNullable (Array PolicyResponse)
434− , sends :: Array SendResponse
429+ , sends :: Array SendResponse
435− }
436−
437−type FolderResponse
438− = { id :: String
439− , name :: JNullable String
440− , revisionDate :: JNullable String
441− }
430+ }
442
431
443−type CollectionDetailsResponse
432+type FolderResponse =
444− = { id :: String
433+ { id :: String
445− , organizationId :: JNullable String
446− , name :: JNullable String
434+ , name :: JNullable String
447− , externalId :: JNullable String
435+ , revisionDate :: JNullable String
448− , readOnly :: Boolean
449− }
436+ }
450
437
438+type CollectionDetailsResponse =
439+ { id :: String
440+ , organizationId :: JNullable String
441+ , name :: JNullable String
442+ , externalId :: JNullable String
443+ , readOnly :: Boolean
444+ }
451
445
452type CipherId = String
446type CipherId = String
453
447
454−type CipherResponse
448+type CipherResponse =
455− = { id :: CipherId
449+ { id :: CipherId
456− , organizationId :: JNullable String
450+ , organizationId :: JNullable String
457− , folderId :: JNullable String
451+ , folderId :: JNullable String
458− , type :: CipherType
452+ , type :: CipherType
459− , name :: EncryptedString
453+ , name :: EncryptedString
460− , notes :: JNullable EncryptedString
454+ , notes :: JNullable EncryptedString
461− , fields :: JNullable (Array FieldApi)
455+ , fields :: JNullable (Array FieldApi)
462− , login :: JNullable LoginApi
456+ , login :: JNullable LoginApi
463− , card :: JNullable CardApi
457+ , card :: JNullable CardApi
464− , identity :: JNullable IdentityApi
458+ , identity :: JNullable IdentityApi
465− , secureNote :: JNullable SecureNoteApi
459+ , secureNote :: JNullable SecureNoteApi
466− , favorite :: Boolean
460+ , favorite :: Boolean
467− , edit :: JNullable Boolean
461+ , edit :: JNullable Boolean
468− , viewPassword :: JNullable Boolean
462+ , viewPassword :: JNullable Boolean
469− , organizationUseTotp :: JNullable Boolean
463+ , organizationUseTotp :: JNullable Boolean
470− , revisionDate :: JNullable Timestamp
464+ , revisionDate :: JNullable Timestamp
471− , attachments :: JNullable (Array AttachmentResponse)
465+ , attachments :: JNullable (Array AttachmentResponse)
472− , passwordHistory :: JNullable (Array PasswordHistoryResponse)
466+ , passwordHistory :: JNullable (Array PasswordHistoryResponse)
473− , collectionIds :: JNullable (Array String)
467+ , collectionIds :: JNullable (Array String)
474− , deletedDate :: JNullable String
468+ , deletedDate :: JNullable String
475− , reprompt :: CipherRepromptType
469+ , reprompt :: CipherRepromptType
476− }
470+ }
477
471
478cipherTypeLogin = 1 :: CipherType
472cipherTypeLogin = 1 :: CipherType
479
473
@@ -483,15 +477,14 @@ cipherTypeCard = 3 :: CipherType
483
477
484cipherTypeIdentity = 4 :: CipherType
478cipherTypeIdentity = 4 :: CipherType
485
479
486−type CipherType
480+type CipherType = Int
487− = Int
488
481
489−type FieldApi
482+type FieldApi =
490− = { name :: JNullable String
483+ { name :: JNullable String
491− , value :: JNullable String
484+ , value :: JNullable String
492− , type :: FieldType
485+ , type :: FieldType
493− , linkedId :: JNullable LinkedIdType
486+ , linkedId :: JNullable LinkedIdType
494− }
487+ }
495
488
496fieldTypeText = 0 :: FieldType
489fieldTypeText = 0 :: FieldType
497
490
@@ -501,8 +494,7 @@ fieldTypeBoolean = 2 :: FieldType
501
494
502fieldTypeLinked = 3 :: FieldType
495fieldTypeLinked = 3 :: FieldType
503
496
504−type FieldType
497+type FieldType = Int
505− = Int
506
498
507linkedIdTypeLoginLinkedIdUsername = 100 :: LinkedIdType
499linkedIdTypeLoginLinkedIdUsername = 100 :: LinkedIdType
508
500
@@ -558,23 +550,22 @@ linkedIdTypeIdentityLinkedIdLastName = 417 :: LinkedIdType
558
550
559linkedIdTypeIdentityLinkedIdFullName = 418 :: LinkedIdType
551linkedIdTypeIdentityLinkedIdFullName = 418 :: LinkedIdType
560
552
561−type LinkedIdType
553+type LinkedIdType = Int
562− = Int
563
554
564−type LoginApi
555+type LoginApi =
565− = { uris :: JOpt (Array LoginUriApi)
556+ { uris :: JOpt (Array LoginUriApi)
566− , username :: JNullable EncryptedString
557+ , username :: JNullable EncryptedString
567− , password :: JNullable EncryptedString
558+ , password :: JNullable EncryptedString
568− , passwordRevisionDate :: JNullable String
559+ , passwordRevisionDate :: JNullable String
569− , totp :: JNullable EncryptedString
560+ , totp :: JNullable EncryptedString
570− -- This thing is undefined in some cases for some reson. Just ignoring it
561+ -- This thing is undefined in some cases for some reson. Just ignoring it
571− , autofillOnPageLoad :: JOpt (JNullable Boolean)
562+ , autofillOnPageLoad :: JOpt (JNullable Boolean)
572− }
563+ }
573
564
574−type LoginUriApi
565+type LoginUriApi =
575− = { uri :: EncryptedString
566+ { uri :: JNullable EncryptedString
576− , match :: JNullable UriMatchType
567+ , match :: JNullable UriMatchType
577− }
568+ }
578
569
579uriMatchTypeDomain = 0 :: UriMatchType
570uriMatchTypeDomain = 0 :: UriMatchType
580
571
@@ -588,87 +579,85 @@ uriMatchTypeRegularExpression = 4 :: UriMatchType
588
579
589uriMatchTypeNever = 5 :: UriMatchType
580uriMatchTypeNever = 5 :: UriMatchType
590
581
591−type UriMatchType
582+type UriMatchType = Int
592− = Int
583+
593−
594−type CardApi
584+type CardApi =
595− = { cardholderName :: JNullable EncryptedString
585+ { cardholderName :: JNullable EncryptedString
596− , brand :: JNullable EncryptedString
586+ , brand :: JNullable EncryptedString
597− , number :: JNullable EncryptedString
587+ , number :: JNullable EncryptedString
598− , expMonth :: JNullable EncryptedString
588+ , expMonth :: JNullable EncryptedString
599− , expYear :: JNullable EncryptedString
589+ , expYear :: JNullable EncryptedString
600− , code :: JNullable EncryptedString
590+ , code :: JNullable EncryptedString
601− }
591+ }
602−
592+
603−type IdentityApi
593+type IdentityApi =
604− = { title :: JNullable EncryptedString
594+ { title :: JNullable EncryptedString
605− , firstName :: JNullable EncryptedString
595+ , firstName :: JNullable EncryptedString
606− , middleName :: JNullable EncryptedString
596+ , middleName :: JNullable EncryptedString
607− , lastName :: JNullable EncryptedString
597+ , lastName :: JNullable EncryptedString
608− , address1 :: JNullable EncryptedString
598+ , address1 :: JNullable EncryptedString
609− , address2 :: JNullable EncryptedString
599+ , address2 :: JNullable EncryptedString
610− , address3 :: JNullable EncryptedString
600+ , address3 :: JNullable EncryptedString
611− , city :: JNullable EncryptedString
601+ , city :: JNullable EncryptedString
612− , state :: JNullable EncryptedString
602+ , state :: JNullable EncryptedString
613− , postalCode :: JNullable EncryptedString
603+ , postalCode :: JNullable EncryptedString
614− , country :: JNullable EncryptedString
604+ , country :: JNullable EncryptedString
615− , company :: JNullable EncryptedString
605+ , company :: JNullable EncryptedString
616− , email :: JNullable EncryptedString
606+ , email :: JNullable EncryptedString
617− , phone :: JNullable EncryptedString
607+ , phone :: JNullable EncryptedString
618− , ssn :: JNullable EncryptedString
608+ , ssn :: JNullable EncryptedString
619− , username :: JNullable EncryptedString
609+ , username :: JNullable EncryptedString
620− , passportNumber :: JNullable EncryptedString
610+ , passportNumber :: JNullable EncryptedString
621− , licenseNumber :: JNullable EncryptedString
611+ , licenseNumber :: JNullable EncryptedString
622− }
612+ }
623
613
624secureNoteTypeGeneric = 0 :: SecureNoteType
614secureNoteTypeGeneric = 0 :: SecureNoteType
625
615
626−type SecureNoteType
616+type SecureNoteType = Int
627− = Int
628
617
629−type SecureNoteApi = {
618+type SecureNoteApi =
619+ {
630 -- type :: SecureNoteType
620 -- type :: SecureNoteType
631−}
621+ }
632−
622+
633−type AttachmentResponse
623+type AttachmentResponse =
634− = { id :: String
624+ { id :: String
635− , url :: JNullable String
625+ , url :: JNullable String
636− , fileName :: JNullable String
626+ , fileName :: JNullable String
637− , key :: JNullable String
627+ , key :: JNullable String
638− , size :: JNullable String
628+ , size :: JNullable String
639− , sizeName :: JNullable String
629+ , sizeName :: JNullable String
640− }
630+ }
641−
631+
642−type PasswordHistoryResponse
632+type PasswordHistoryResponse =
643− = { password :: String
633+ { password :: String
644− , lastUsedDate :: JNullable String
634+ , lastUsedDate :: JNullable String
645− }
635+ }
646
636
647cipherRepromptTypeNone = 0 :: CipherRepromptType
637cipherRepromptTypeNone = 0 :: CipherRepromptType
648
638
649cipherRepromptTypePassword = 1 :: CipherRepromptType
639cipherRepromptTypePassword = 1 :: CipherRepromptType
650
640
651−type CipherRepromptType
641+type CipherRepromptType = Int
652− = Int
653
642
654−type DomainsResponse
643+type DomainsResponse =
655− = { equivalentDomains :: Array (Array String)
644+ { equivalentDomains :: Array (Array String)
656− , globalEquivalentDomains :: Array GlobalDomainResponse
645+ , globalEquivalentDomains :: Array GlobalDomainResponse
657− }
646+ }
658
647
659−type GlobalDomainResponse
648+type GlobalDomainResponse =
660− = { type :: Int
649+ { type :: Int
661− , domains :: Array String
650+ , domains :: Array String
662− , excluded :: Boolean
651+ , excluded :: Boolean
663− }
652+ }
664
653
665−type PolicyResponse
654+type PolicyResponse =
666− = { id :: String
655+ { id :: String
667− , organizationId :: JNullable String
656+ , organizationId :: JNullable String
668− , type :: PolicyType
657+ , type :: PolicyType
669− , data :: ShowableJson
658+ , data :: ShowableJson
670− , enabled :: Boolean
659+ , enabled :: Boolean
671− }
660+ }
672
661
673policyTypeTwoFactorAuthentication = 0 :: PolicyType -- Requires users to have 2fa enabled
662policyTypeTwoFactorAuthentication = 0 :: PolicyType -- Requires users to have 2fa enabled
674
663
@@ -692,46 +681,44 @@ policyTypeMaximumVaultTimeout = 9 :: PolicyType -- Sets the maximum allowed vaul
692
681
693policyTypeDisablePersonalVaultExport = 10 :: PolicyType -- Disable personal vault export
682policyTypeDisablePersonalVaultExport = 10 :: PolicyType -- Disable personal vault export
694
683
695−type PolicyType
684+type PolicyType = Int
696− = Int
685+
697−
698−type SendResponse
686+type SendResponse =
699− = { id :: String
687+ { id :: String
700− , accessId :: JNullable String
688+ , accessId :: JNullable String
701− , type :: SendType
689+ , type :: SendType
702− , name :: JNullable String
690+ , name :: JNullable String
703− , notes :: JNullable String
691+ , notes :: JNullable String
704− , file :: JNullable SendFileApi
692+ , file :: JNullable SendFileApi
705− , text :: JNullable SendTextApi
693+ , text :: JNullable SendTextApi
706− , key :: JNullable String
694+ , key :: JNullable String
707− , maxAccessCount :: JNullable Int
695+ , maxAccessCount :: JNullable Int
708− , accessCount :: JNullable Int
696+ , accessCount :: JNullable Int
709− , revisionDate :: JNullable String
697+ , revisionDate :: JNullable String
710− , expirationDate :: JNullable String
698+ , expirationDate :: JNullable String
711− , deletionDate :: JNullable String
699+ , deletionDate :: JNullable String
712− , password :: JNullable String
700+ , password :: JNullable String
713− , disable :: Boolean
701+ , disable :: Boolean
714− , hideEmail :: Boolean
702+ , hideEmail :: Boolean
715− }
703+ }
716
704
717sendTypeText = 0 :: SendType
705sendTypeText = 0 :: SendType
718
706
719sendTypeFile = 1 :: SendType
707sendTypeFile = 1 :: SendType
720
708
721−type SendType
709+type SendType = Int
722− = Int
723
710
724−type SendFileApi
711+type SendFileApi =
725− = { id :: String
712+ { id :: String
726− , fileName :: JNullable String
713+ , fileName :: JNullable String
727− , size :: JNullable String
714+ , size :: JNullable String
728− , sizeName :: JNullable String
715+ , sizeName :: JNullable String
729− }
716+ }
730
717
731−type SendTextApi
718+type SendTextApi =
732− = { text :: JNullable String
719+ { text :: JNullable String
733− , hidden :: Boolean
720+ , hidden :: Boolean
734− }
721+ }
735
722
736type TwoFactorEmailRequest =
723type TwoFactorEmailRequest =
737 { email :: Email
724 { email :: Email
backend/Data/EncString.js+1−1
@@ -1,4 +1,4 @@
1−import { EncString } from "../../deps/bw/libs/shared/dist/src/models/domain/encString"
1+import { EncString } from "../../bw/models/domain/enc-string"
2
2
3export function fromString(str) {
3export function fromString(str) {
4 const x = new EncString(str)
4 const x = new EncString(str)
backend/Data/SymmetricCryptoKey.js+1−1
@@ -1,4 +1,4 @@
1−import { SymmetricCryptoKey } from '../../deps/bw/libs/shared/dist/src/models/domain/symmetricCryptoKey.js'
1+import { SymmetricCryptoKey } from '../../bw/models/domain/symmetric-crypto-key.js'
2
2
3export function fromArrayBuffer(arr) {
3export function fromArrayBuffer(arr) {
4 return new SymmetricCryptoKey(arr)
4 return new SymmetricCryptoKey(arr)
backend/Main.purs+136−124
@@ -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
@@ -131,7 +132,10 @@ main = do
131 }
132 }
132 pure $ Right resp
133 pure $ Right resp
133 )
134 )
135+ ( \err -> do
136+ log $ show err
134− (const $ pure $ Left unit)
137+ pure $ Left unit
138+ )
135 case map (toEither1 >>> map toEither1) $ loginResponse of
139 case map (toEither1 >>> map toEither1) $ loginResponse of
136 Left _ -> send Bridge.WrongPassword
140 Left _ -> send Bridge.WrongPassword
137 Right (Left { siteKey }) -> send $ Bridge.NeedsCaptcha siteKey
141 Right (Left { siteKey }) -> send $ Bridge.NeedsCaptcha siteKey
@@ -182,9 +186,9 @@ main = do
182 Bridge.Init -> do
186 Bridge.Init -> do
183 Storage.get storage TokenKey
187 Storage.get storage TokenKey
184 >>= \x ->
188 >>= \x ->
185− Elm.send app case x of
189+ Elm.send app case x of
186− Just _ -> Bridge.LoginSuccessful
190+ Just _ -> Bridge.LoginSuccessful
187− Nothing -> Bridge.NeedsLogin
191+ Nothing -> Bridge.NeedsLogin
188 Bridge.RequestCipher id ->
192 Bridge.RequestCipher id ->
189 runWithDecryptionKey do
193 runWithDecryptionKey do
190 sync <- getOrReset SyncKey
194 sync <- getOrReset SyncKey
@@ -192,8 +196,7 @@ main = do
192 Nothing -> pure unit
196 Nothing -> pure unit
193 Just cipherResponse -> do
197 Just cipherResponse -> do
194 cipher <- decodeCipher cipherResponse
198 cipher <- decodeCipher cipherResponse
195− send $ Bridge.LoadCipher cipher
199+ for_ cipher $ send <<< Bridge.LoadCipher
196− pure unit
197 pure unit
200 pure unit
198 Bridge.NeedEmail ->
201 Bridge.NeedEmail ->
199 runWithDecryptionKey do
202 runWithDecryptionKey do
@@ -209,7 +212,7 @@ main = do
209 api <- getAuthedApi
212 api <- getAuthedApi
210 cipher <- encodeCipher fullCipher
213 cipher <- encodeCipher fullCipher
211 newCipher <- liftPromise (api.putCipher cipher) >>= decodeCipher
214 newCipher <- liftPromise (api.putCipher cipher) >>= decodeCipher
212− send $ Bridge.CipherChanged newCipher
215+ for_ newCipher $ send <<< Bridge.CipherChanged
213 performSync
216 performSync
214 pure unit
217 pure unit
215 Bridge.GeneratePassword cfg ->
218 Bridge.GeneratePassword cfg ->
@@ -222,7 +225,7 @@ main = do
222 api <- getAuthedApi
225 api <- getAuthedApi
223 cipher <- encodeCipher fullCipher
226 cipher <- encodeCipher fullCipher
224 newCipher <- liftPromise (api.postCipherCreate cipher) >>= decodeCipher
227 newCipher <- liftPromise (api.postCipherCreate cipher) >>= decodeCipher
225− send $ Bridge.CipherChanged newCipher
228+ for_ newCipher $ send <<< Bridge.CipherChanged
226 performSync
229 performSync
227 pure unit
230 pure unit
228 Bridge.DeleteCipher c@(Bridge.FullCipher { id }) ->
231 Bridge.DeleteCipher c@(Bridge.FullCipher { id }) ->
@@ -240,14 +243,20 @@ main = do
240 interval = totpService.getTimeInterval totp
243 interval = totpService.getTimeInterval totp
241 send $ Bridge.Totp
244 send $ Bridge.Totp
242 $ Bridge.Sub_Totp
245 $ Bridge.Sub_Totp
246+ { interval
247+ , code
243− { interval, code, source: totp
248+ , source: totp
244 }
249 }
245 pure unit
250 pure unit
246 Bridge.ChooseSecondFactor
251 Bridge.ChooseSecondFactor
247 ( Bridge.Cmd_ChooseSecondFactor
252 ( Bridge.Cmd_ChooseSecondFactor
253+ { email: email'
254+ , factor
255+ , server
256+ , password
248− { email: email', factor, server, password, requestFromServer
257+ , requestFromServer
249− }
258+ }
250− ) ->
259+ ) ->
251 when requestFromServer
260 when requestFromServer
252 let
261 let
253 email = Email email'
262 email = Email email'
@@ -264,17 +273,18 @@ main = do
264 pure unit
273 pure unit
265 _ -> pure unit
274 _ -> pure unit
266
275
267−processCipher ::
276+processCipher
268− forall r.
277+ :: forall r
269− CipherResponse ->
278+ . CipherResponse
270− Run
279+ -> Run
271− ( crypto :: Reader CryptoService
280+ ( crypto :: Reader CryptoService
272− , key :: Reader SymmetricCryptoKey
281+ , key :: Reader SymmetricCryptoKey
273− , aff :: Aff
282+ , aff :: Aff
274− , effect :: Effect
283+ , effect :: Effect
275− | r
284+ | r
276− )
285+ )
277− { cipher :: Bridge.Sub_LoadCiphers, date :: DateTime }
286+ (Maybe { cipher :: Bridge.Sub_LoadCiphers, date :: DateTime })
287+processCipher cipher | not (supportedCipher cipher) = pure Nothing
278processCipher cipher = do
288processCipher cipher = do
279 name <- decrypt cipher.name
289 name <- decrypt cipher.name
280 cipherType <- case cipher.type of
290 cipherType <- case cipher.type of
@@ -289,7 +299,9 @@ processCipher cipher = do
289 n -> liftEffect $ throw $ "Unsupported cipher type: " <> show n
299 n -> liftEffect $ throw $ "Unsupported cipher type: " <> show n
290 date <- liftEffect $ maybe (pure bottom) (Timestamp.toDateTime) $ JNullable.toMaybe cipher.revisionDate
300 date <- liftEffect $ maybe (pure bottom) (Timestamp.toDateTime) $ JNullable.toMaybe cipher.revisionDate
291 pure
301 pure
302+ $ Just
303+ $
292− $ { cipher:
304+ { cipher:
293 Bridge.Sub_LoadCiphers
305 Bridge.Sub_LoadCiphers
294 { name: name
306 { name: name
295 , date: maybe "" Timestamp.toLocalDateTimeString $ JNullable.toMaybe cipher.revisionDate
307 , date: maybe "" Timestamp.toLocalDateTimeString $ JNullable.toMaybe cipher.revisionDate
@@ -323,18 +335,18 @@ baseUrl server =
323 , keyConnector: jnull
335 , keyConnector: jnull
324 }
336 }
325
337
326−getOrReset ::
338+getOrReset
327− forall k t r.
339+ :: forall k t r
328− StorageKey k t =>
340+ . StorageKey k t
329− DecodeJson t =>
341+ => DecodeJson t
330− k ->
342+ => k
331− Run
343+ -> Run
332− ( storage :: Reader Storage
344+ ( storage :: Reader Storage
333− , app :: Reader Elm
345+ , app :: Reader Elm
334− , effect :: Effect
346+ , effect :: Effect
335− | r
347+ | r
336− )
348+ )
337− t
349+ t
338getOrReset key = do
350getOrReset key = do
339 storage <- askAt (Proxy :: _ "storage")
351 storage <- askAt (Proxy :: _ "storage")
340 app <- askAt (Proxy :: _ "app")
352 app <- askAt (Proxy :: _ "app")
@@ -345,69 +357,69 @@ getOrReset key = do
345 Exc.throw "Encountered an internal error. Resetting the app."
357 Exc.throw "Encountered an internal error. Resetting the app."
346 liftEffect $ try (Storage.get storage key)
358 liftEffect $ try (Storage.get storage key)
347 >>= \x -> case x of
359 >>= \x -> case x of
348− Left err -> do
360+ Left err -> do
349− log $ show err
361+ log $ show err
350− handleError
362+ handleError
351− Right Nothing -> handleError
363+ Right Nothing -> handleError
352− Right (Just y) -> pure y
364+ Right (Just y) -> pure y
353
365
354−getAuthedApi ::
366+getAuthedApi
355− forall r.
367+ :: forall r
356− Run
368+ . Run
357− ( storage :: Reader Storage
369+ ( storage :: Reader Storage
358− , app :: Reader Elm
370+ , app :: Reader Elm
359− , aff :: Aff
371+ , aff :: Aff
360− , effect :: Effect
372+ , effect :: Effect
361− , services :: Reader Services
373+ , services :: Reader Services
362− | r
374+ | r
363− )
375+ )
364− ApiService
376+ ApiService
365getAuthedApi = do
377getAuthedApi = do
366 services <- askAt (Proxy :: _ "services")
378 services <- askAt (Proxy :: _ "services")
367 token <- getOrReset TokenKey
379 token <- getOrReset TokenKey
368 url <- getOrReset UrlsKey
380 url <- getOrReset UrlsKey
369 liftPromise $ services.getApi (baseUrl url) (nullify token)
381 liftPromise $ services.getApi (baseUrl url) (nullify token)
370
382
371−requestMasterPassword ::
383+requestMasterPassword
372− forall r.
384+ :: forall r
373− Run
385+ . Run
374− ( storage :: Reader Storage
386+ ( storage :: Reader Storage
375− , app :: Reader Elm
387+ , app :: Reader Elm
376− , effect :: Effect
388+ , effect :: Effect
377− | r
389+ | r
378− )
390+ )
379− Unit
391+ Unit
380requestMasterPassword = do
392requestMasterPassword = do
381 url <- getOrReset UrlsKey
393 url <- getOrReset UrlsKey
382 sync <- getOrReset SyncKey
394 sync <- getOrReset SyncKey
383 send $ Bridge.NeedsMasterPassword $ Bridge.Sub_NeedsMasterPassword { server: url, login: sync.profile.email }
395 send $ Bridge.NeedsMasterPassword $ Bridge.Sub_NeedsMasterPassword { server: url, login: sync.profile.email }
384
396
385−send ::
397+send
386− forall r.
398+ :: forall r
387− Bridge.Sub ->
399+ . Bridge.Sub
388− Run
400+ -> Run
389− ( app :: Reader Elm
401+ ( app :: Reader Elm
390− , effect :: Effect
402+ , effect :: Effect
391− | r
403+ | r
392− )
404+ )
393− Unit
405+ Unit
394send sub = do
406send sub = do
395 app <- askAt (Proxy :: _ "app")
407 app <- askAt (Proxy :: _ "app")
396 liftEffect $ Elm.send app sub
408 liftEffect $ Elm.send app sub
397
409
398−performSync ::
410+performSync
399− forall r.
411+ :: forall r
400− Run
412+ . Run
401− ( storage :: Reader Storage
413+ ( storage :: Reader Storage
402− , app :: Reader Elm
414+ , app :: Reader Elm
403− , aff :: Aff
415+ , aff :: Aff
404− , effect :: Effect
416+ , effect :: Effect
405− , services :: Reader Services
417+ , services :: Reader Services
406− , crypto :: Reader CryptoService
418+ , crypto :: Reader CryptoService
407− , key :: Reader SymmetricCryptoKey
419+ , key :: Reader SymmetricCryptoKey
408− | r
420+ | r
409− )
421+ )
410− Unit
422+ Unit
411performSync = do
423performSync = do
412 api <- getAuthedApi
424 api <- getAuthedApi
413 storage <- askAt (Proxy :: _ "storage")
425 storage <- askAt (Proxy :: _ "storage")
@@ -415,22 +427,22 @@ performSync = do
415 liftEffect $ Storage.store storage SyncKey newSync
427 liftEffect $ Storage.store storage SyncKey newSync
416 sendCiphers
428 sendCiphers
417
429
418−sendCiphers ::
430+sendCiphers
419− forall r.
431+ :: forall r
420− Run
432+ . Run
421− ( storage :: Reader Storage
433+ ( storage :: Reader Storage
422− , app :: Reader Elm
434+ , app :: Reader Elm
423− , aff :: Aff
435+ , aff :: Aff
424− , effect :: Effect
436+ , effect :: Effect
425− , services :: Reader Services
437+ , services :: Reader Services
426− , crypto :: Reader CryptoService
438+ , crypto :: Reader CryptoService
427− , key :: Reader SymmetricCryptoKey
439+ , key :: Reader SymmetricCryptoKey
428− | r
440+ | r
429− )
441+ )
430− Unit
442+ Unit
431sendCiphers = do
443sendCiphers = do
432 sync <- getOrReset SyncKey
444 sync <- getOrReset SyncKey
433− ciphers <- traverse processCipher sync.ciphers
445+ ciphers <- Array.catMaybes <$> traverse processCipher sync.ciphers
434 let
446 let
435 sortedCiphers = Array.sortWith (_.date >>> Down) ciphers
447 sortedCiphers = Array.sortWith (_.date >>> Down) ciphers
436 send $ Bridge.LoadCiphers $ Bridge.Sub_LoadCiphers_List $ map _.cipher sortedCiphers
448 send $ Bridge.LoadCiphers $ Bridge.Sub_LoadCiphers_List $ map _.cipher sortedCiphers
backend/Storage.purs+7−1
@@ -2,7 +2,7 @@ module Storage where
2
2
3import Prelude
3import Prelude
4
4
5−import BW (Hash(..))
5+import BW (Hash)
6import BW.Types (IdentityTokenResponse, SyncResponse, PreloginResponse)
6import BW.Types (IdentityTokenResponse, SyncResponse, PreloginResponse)
7import Localstorage (class StorageKey)
7import Localstorage (class StorageKey)
8
8
@@ -35,3 +35,9 @@ data MasterPasswordHashKey
35
35
36instance StorageKey MasterPasswordHashKey Hash where
36instance StorageKey MasterPasswordHashKey Hash where
37 storageKey MasterPasswordHashKey = "master-password-hash"
37 storageKey MasterPasswordHashKey = "master-password-hash"
38+
39+data DeviceIDKey
40+ = DeviceIDKey
41+
42+instance StorageKey DeviceIDKey String where
43+ storageKey DeviceIDKey = "device-uuid"
build.sh+2−14
@@ -1,17 +1,5 @@
1−#!/bin/bash
1+#!/bin/sh
2
2
3set -e
3set -e
4
4
5−TEMP=$(mktemp -d)
5+cp -r "$SRC_DIR/dist"/* "$INSTALL_DIR"
6−
7−cp -r "$SRC_DIR"/{warden.apparmor,warden.desktop,manifest.json,logo.png,index.html,style.css} "$INSTALL_DIR"
8−mkdir -p "$INSTALL_DIR"/vanilla
9−cp -r "$SRC_DIR"/vanilla/dist "$INSTALL_DIR"/vanilla
10−
11−elm make "$SRC_DIR/frontend/Main.elm" --optimize --output="$TEMP/elm.js"
12−
13−terser "$TEMP/elm.js" --ecma 2018 --compress 'pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters,keep_fargs=false,unsafe_comps,unsafe' | terser --ecma 2018 --mangle --compress --output "$INSTALL_DIR/elm.js"
14−
15−(cd "$SRC_DIR" && spago bundle-app --to "$TEMP/backend.js")
16−
17−terser "$TEMP/backend.js" --ecma 2018 --mangle --compress 'drop_console=true' --comments=false --toplevel --output "$INSTALL_DIR/backend.js"
clickable.yaml+2−10
@@ -1,16 +1,8 @@
1clickable_minimum_required: 7.1.2
1clickable_minimum_required: 7.1.2
2+framework: ubuntu-sdk-20.04
2builder: custom
3builder: custom
3build: $SRC_DIR/build.sh
4build: $SRC_DIR/build.sh
4kill: webapp-container*
5kill: webapp-container*
5−image_setup:
6+docker_image: clickable/amd64-20.04-amd64
6− env: {}
7− # DEB_URL: http://archive.ubuntu.com/ubuntu
8− # HOST_ARCH: amd64
9−
10− # PATH: /opt/someprogram/bin:$PATH
11− run:
12−
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/)
14− - npm install -g spago esbuild purescript terser --unsafe-perm=true
15
7
16restrict_arch: all
8restrict_arch: all
deps/bwdeleted−1

Submodule changed.

dev/build-backend.sh+7−1
@@ -1,3 +1,9 @@
1#!/bin/sh
1#!/bin/sh
2
2
3−spago bundle-app --source-maps --purs-args "-g sourcemaps" --to backend.js
3+set -e
4+
5+spago build
6+
7+export out="$(pwd)/backend.js"
8+
9+$(nix build .#backendBuildScript --print-out-paths) "$(pwd)/output"
dev/build.shnew file+10
@@ -0,0 +1,10 @@
1+#!/bin/sh
2+
3+
4+rm -r dist
5+
6+mkdir -p dist
7+
8+cp -r "$(nix build ".#warden-click-src" --print-out-paths)"/* dist
9+
10+chmod -R 777 dist
dev/elm-live.sh+4
@@ -1,3 +1,7 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+set -e
4+
5+nix build .#vanilla -o vanilla
6+
3nix run github:NixOS/nixpkgs?rev=d9a1414346059619d9e13ab93e749bbb82e5252a#elmPackages.elm-live -- $1 --start-page=index.html --proxy-prefix=/api --proxy-host=http://localhost:6009 -- --debug --output=elm.js
7nix run github:NixOS/nixpkgs?rev=d9a1414346059619d9e13ab93e749bbb82e5252a#elmPackages.elm-live -- $1 --start-page=index.html --proxy-prefix=/api --proxy-host=http://localhost:6009 -- --debug --output=elm.js
dev/elm2nix.shnew file+8
@@ -0,0 +1,8 @@
1+#!/bin/sh
2+
3+set -e
4+
5+cd "$(dirname "$0")/.."
6+
7+nix run github:NixOS/nixpkgs#elm2nix -- snapshot
8+nix run github:NixOS/nixpkgs#elm2nix -- convert > elm-srcs.nix
dev/spago2nix.shnew file+3
@@ -0,0 +1,3 @@
1+#!/bin/sh
2+
3+nix run "github:justinwoo/spago2nix#spago2nix" -- generate
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
elm-srcs.nixnew file+62
@@ -0,0 +1,62 @@
1+{
2+
3+ "FabienHenon/elm-infinite-scroll" = {
4+ sha256 = "0vhh7j3lna05l5hwjazag52lbkjv11s80jj62m9wb53qxkarw948";
5+ version = "3.0.3";
6+ };
7+
8+ "bartavelle/json-helpers" = {
9+ sha256 = "0k96qra2nq1j4j4ahfl98dkpkc6f2831mq5d5xxg27mp31qwq5nn";
10+ version = "2.0.2";
11+ };
12+
13+ "elm/browser" = {
14+ sha256 = "0nagb9ajacxbbg985r4k9h0jadqpp0gp84nm94kcgbr5sf8i9x13";
15+ version = "1.0.2";
16+ };
17+
18+ "elm/core" = {
19+ sha256 = "19w0iisdd66ywjayyga4kv2p1v9rxzqjaxhckp8ni6n8i0fb2dvf";
20+ version = "1.0.5";
21+ };
22+
23+ "elm/html" = {
24+ sha256 = "1n3gpzmpqqdsldys4ipgyl1zacn0kbpc3g4v3hdpiyfjlgh8bf3k";
25+ version = "1.0.0";
26+ };
27+
28+ "elm/json" = {
29+ sha256 = "0kjwrz195z84kwywaxhhlnpl3p251qlbm5iz6byd6jky2crmyqyh";
30+ version = "1.1.3";
31+ };
32+
33+ "elm/time" = {
34+ sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1";
35+ version = "1.0.0";
36+ };
37+
38+ "mdgriffith/elm-ui" = {
39+ sha256 = "0ffcqv4a4ad400hwp824m3qq4jy82cqp5ghmhp1m0q7n004z6kgv";
40+ version = "1.1.8";
41+ };
42+
43+ "mgold/elm-nonempty-list" = {
44+ sha256 = "02d3xgasgy5knh02rgl403z9hwlbyrsnp9wavc2lhkxxa2misrgl";
45+ version = "4.2.0";
46+ };
47+
48+ "elm/random" = {
49+ sha256 = "138n2455wdjwa657w6sjq18wx2r0k60ibpc4frhbqr50sncxrfdl";
50+ version = "1.0.0";
51+ };
52+
53+ "elm/url" = {
54+ sha256 = "0av8x5syid40sgpl5vd7pry2rq0q4pga28b4yykn9gd9v12rs3l4";
55+ version = "1.0.0";
56+ };
57+
58+ "elm/virtual-dom" = {
59+ sha256 = "1yvb8px2z62xd578ag2q0r5hd1vkz9y7dfkx05355iiy1d7jwq4v";
60+ version = "1.0.3";
61+ };
62+}
flake.locknew file+177
@@ -0,0 +1,177 @@
1+{
2+ "nodes": {
3+ "bw": {
4+ "flake": false,
5+ "locked": {
6+ "lastModified": 1675446731,
7+ "narHash": "sha256-IbFjYNYZep6W9c+dztJ9CXrwQ0cep3EKb6qnEvv4pj4=",
8+ "owner": "bitwarden",
9+ "repo": "clients",
10+ "rev": "ff143760d4f527f2349333ee4b3004eeda68fac5",
11+ "type": "github"
12+ },
13+ "original": {
14+ "owner": "bitwarden",
15+ "repo": "clients",
16+ "rev": "ff143760d4f527f2349333ee4b3004eeda68fac5",
17+ "type": "github"
18+ }
19+ },
20+ "easy-ps": {
21+ "flake": false,
22+ "locked": {
23+ "lastModified": 1671011575,
24+ "narHash": "sha256-tESal32bcqqdZO+aKnBzc1GoL2mtnaDtj2y7ociCRGA=",
25+ "owner": "justinwoo",
26+ "repo": "easy-purescript-nix",
27+ "rev": "11d3bd58ce6e32703bf69cec04dc7c38eabe14ba",
28+ "type": "github"
29+ },
30+ "original": {
31+ "owner": "justinwoo",
32+ "repo": "easy-purescript-nix",
33+ "type": "github"
34+ }
35+ },
36+ "easy-purescript-nix": {
37+ "flake": false,
38+ "locked": {
39+ "lastModified": 1670198178,
40+ "narHash": "sha256-5KkyNpPakv4xIP2ba0S5GX+dcmd3AcO9kPhwa482BbA=",
41+ "owner": "justinwoo",
42+ "repo": "easy-purescript-nix",
43+ "rev": "7a4cb3cd6ca53566ea1675692eab0aa13907ff09",
44+ "type": "github"
45+ },
46+ "original": {
47+ "owner": "justinwoo",
48+ "repo": "easy-purescript-nix",
49+ "type": "github"
50+ }
51+ },
52+ "flake-utils": {
53+ "locked": {
54+ "lastModified": 1676283394,
55+ "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
56+ "owner": "numtide",
57+ "repo": "flake-utils",
58+ "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
59+ "type": "github"
60+ },
61+ "original": {
62+ "owner": "numtide",
63+ "repo": "flake-utils",
64+ "type": "github"
65+ }
66+ },
67+ "flake-utils_2": {
68+ "locked": {
69+ "lastModified": 1667395993,
70+ "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
71+ "owner": "numtide",
72+ "repo": "flake-utils",
73+ "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
74+ "type": "github"
75+ },
76+ "original": {
77+ "owner": "numtide",
78+ "repo": "flake-utils",
79+ "type": "github"
80+ }
81+ },
82+ "nix-filter": {
83+ "locked": {
84+ "lastModified": 1676294984,
85+ "narHash": "sha256-hdLUa/3RH1VJ+gMUysQE0JGM4F2Q/tIIFbtoxAOurJQ=",
86+ "owner": "numtide",
87+ "repo": "nix-filter",
88+ "rev": "fc282c5478e4141842f9644c239a41cfe9586732",
89+ "type": "github"
90+ },
91+ "original": {
92+ "owner": "numtide",
93+ "repo": "nix-filter",
94+ "type": "github"
95+ }
96+ },
97+ "nixpkgs": {
98+ "locked": {
99+ "lastModified": 1677080879,
100+ "narHash": "sha256-0SjW4/d3Rkw6C7hHZ5lxT4r6Pw9vzQb6Il6zYWwe2Bo=",
101+ "owner": "NixOS",
102+ "repo": "nixpkgs",
103+ "rev": "f5dad40450d272a1ea2413f4a67ac08760649e89",
104+ "type": "github"
105+ },
106+ "original": {
107+ "id": "nixpkgs",
108+ "type": "indirect"
109+ }
110+ },
111+ "nixpkgs_2": {
112+ "locked": {
113+ "lastModified": 1670507980,
114+ "narHash": "sha256-riNZa0xzM1it3pzxciwALeMs+0CsBMWIW2FqulzK8vM=",
115+ "owner": "NixOS",
116+ "repo": "nixpkgs",
117+ "rev": "2787fc7d1e51404678614bf0fe92fc296746eec0",
118+ "type": "github"
119+ },
120+ "original": {
121+ "owner": "NixOS",
122+ "ref": "nixos-unstable",
123+ "repo": "nixpkgs",
124+ "type": "github"
125+ }
126+ },
127+ "root": {
128+ "inputs": {
129+ "bw": "bw",
130+ "easy-ps": "easy-ps",
131+ "flake-utils": "flake-utils",
132+ "nix-filter": "nix-filter",
133+ "nixpkgs": "nixpkgs",
134+ "spago2nix": "spago2nix",
135+ "vanilla": "vanilla"
136+ }
137+ },
138+ "spago2nix": {
139+ "inputs": {
140+ "easy-purescript-nix": "easy-purescript-nix",
141+ "flake-utils": "flake-utils_2",
142+ "nixpkgs": "nixpkgs_2"
143+ },
144+ "locked": {
145+ "lastModified": 1671225584,
146+ "narHash": "sha256-h9r67pmvDuA3TV9299L4CN60XSm8RRtX1EwUoKu9Pyw=",
147+ "owner": "justinwoo",
148+ "repo": "spago2nix",
149+ "rev": "1b8ec352bc7eac077b934d6b9f6efa0129926e59",
150+ "type": "github"
151+ },
152+ "original": {
153+ "owner": "justinwoo",
154+ "repo": "spago2nix",
155+ "type": "github"
156+ }
157+ },
158+ "vanilla": {
159+ "flake": false,
160+ "locked": {
161+ "lastModified": 1663430347,
162+ "narHash": "sha256-J+KyCcCMdC8SYINKAtUsNfM0/lnbwOnsY8TKOP+yY0s=",
163+ "owner": "ilyakooo0",
164+ "repo": "vanilla-compiled",
165+ "rev": "7a0ee46ce9b958b51c57b37c46e86a0a1868bfa9",
166+ "type": "github"
167+ },
168+ "original": {
169+ "owner": "ilyakooo0",
170+ "repo": "vanilla-compiled",
171+ "type": "github"
172+ }
173+ }
174+ },
175+ "root": "root",
176+ "version": 7
177+}
flake.nixnew file+133
@@ -0,0 +1,133 @@
1+{
2+ inputs = {
3+ flake-utils.url = "github:numtide/flake-utils";
4+ bw = {
5+ url =
6+ # Afer this commit they started requiring path at the top level and I can't deal with this right now
7+ "github:bitwarden/clients?rev=ff143760d4f527f2349333ee4b3004eeda68fac5";
8+ flake = false;
9+ };
10+ spago2nix.url = "github:justinwoo/spago2nix";
11+ easy-ps = {
12+ url = "github:justinwoo/easy-purescript-nix";
13+ flake = false;
14+ };
15+ vanilla = {
16+ url = "github:ilyakooo0/vanilla-compiled";
17+ flake = false;
18+ };
19+ nix-filter.url = "github:numtide/nix-filter";
20+ };
21+
22+ outputs = inputs@{ self, nixpkgs, flake-utils, spago2nix, ... }:
23+ flake-utils.lib.eachDefaultSystem (system:
24+ let
25+ pkgs = import nixpkgs { inherit system; };
26+ spagoPkgs = pkgs.callPackage ./spago-packages.nix { };
27+ easy-ps = pkgs.callPackage inputs.easy-ps { };
28+ nix-filter = import inputs.nix-filter;
29+
30+ bw = pkgs.buildNpmPackage {
31+ pname = "bw";
32+ version = "latest";
33+ npmDepsHash = "sha256-jQvL7/SzXqVk03ncU6Mxq8lqFFy+lIrF2QheheXrQ0w=";
34+ makeCacheWritable = true;
35+ src = inputs.bw;
36+ nativeBuildInputs = [ pkgs.python3 ];
37+ buildPhase = ''
38+ (cd libs/common/ && rm -r spec && find . -name "*.spec.ts" -exec rm {} \; && npm exec -c "tsc -m es2020 -t es2018") '';
39+ installPhase = ''
40+ mkdir -p $out
41+ cp -r libs/shared/dist/* $out
42+ cp -r node_modules $out/node_modules
43+ cp package.json $out/package.json
44+ '';
45+ ELECTRON_SKIP_BINARY_DOWNLOAD = 1;
46+ };
47+
48+ backendBuildScript = pkgs.writeScript "build-backend.sh" ''
49+ workdir=$(mktemp -d)
50+ (
51+ cd $workdir
52+ cp -r $1 ./backend
53+ cp -r ${bw} ./bw
54+ cp ${./backend-main.js} backend.js
55+ ${pkgs.esbuild}/bin/esbuild backend.js --bundle --define:ENVIRONMENT_IS_WEB=true --define:ENVIRONMENT_IS_WORKER=false --define:ENVIRONMENT_IS_NODE=false --define:ENVIRONMENT_IS_SHELL=false --external:fs --external:path --loader:.wasm=base64 --outfile=$out
56+ )
57+
58+ '';
59+ backend-js = pkgs.stdenv.mkDerivation {
60+ name = "backend-js";
61+ buildInputs =
62+ [ spagoPkgs.installSpagoStyle spagoPkgs.buildSpagoStyle ];
63+ nativeBuildInputs = [ easy-ps.purs-0_15_7 easy-ps.spago ];
64+ src = nix-filter {
65+ root = ./.;
66+ include = [
67+ ./spago.dhall
68+ ./packages.dhall
69+ (nix-filter.inDirectory ./backend)
70+ ];
71+ };
72+ unpackPhase = ''
73+ cp $src/spago.dhall .
74+ cp $src/packages.dhall .
75+ cp -r $src/backend .
76+ install-spago-style
77+ '';
78+ buildPhase = ''
79+ build-spago-style "./backend/**/*.purs"
80+ '';
81+ installPhase = ''
82+ mkdir $out
83+ cp -r output/* $out/
84+ '';
85+ };
86+
87+ backend =
88+ pkgs.runCommand "backend.js" { buildInputs = [ pkgs.esbuild ]; } ''
89+ ${backendBuildScript} ${backend-js}
90+ '';
91+
92+ frontend = pkgs.callPackage ./frontend.nix { inherit nix-filter; };
93+
94+ warden-src = pkgs.runCommand "warden-src" { } ''
95+ mkdir -p $out
96+
97+ cp ${backend} $out/backend.js
98+ cp -r ${frontend}/Main.min.js $out/elm.js
99+ cp ${./index.html} $out/index.html
100+ cp ${./style.css} $out/style.css
101+ cp -r ${inputs.vanilla} $out/vanilla
102+ '';
103+
104+ warden-click-src = pkgs.runCommand "warden-click-src" { } ''
105+ mkdir -p $out
106+
107+ cp ${./warden.apparmor} $out/warden.apparmor
108+ cp ${./warden.desktop} $out/warden.desktop
109+ cp ${./manifest.json} $out/manifest.json
110+ cp ${./logo.png} $out/logo.png
111+ cp -r ${warden-src}/* $out/
112+ '';
113+
114+ warden = pkgs.writeScript "warden" ''
115+ ${pkgs.electron}/bin/electron ${warden-src}/index.html
116+ '';
117+
118+ in {
119+ packages = {
120+ inherit bw frontend warden-src backendBuildScript warden-click-src;
121+ vanilla = inputs.vanilla.outPath;
122+ };
123+ apps = {
124+ inherit (spago2nix.apps.${system}) spago2nix;
125+ warden = {
126+ type = "app";
127+ program = warden.outPath;
128+ };
129+ };
130+
131+ devShells.default = import ./shell.nix { inherit pkgs; };
132+ });
133+}
frontend.nixnew file+49
@@ -0,0 +1,49 @@
1+{ pkgs, nix-filter }:
2+with pkgs;
3+
4+let
5+ mkDerivation = { srcs ? ./elm-srcs.nix, src, name, srcdir ? "./frontend"
6+ , targets ? [ ], registryDat ? ./registry.dat, outputJavaScript ? true }:
7+ stdenv.mkDerivation {
8+ inherit name src;
9+
10+ buildInputs = [ elmPackages.elm ]
11+ ++ lib.optional outputJavaScript nodePackages.uglify-js;
12+
13+ buildPhase = pkgs.elmPackages.fetchElmDeps {
14+ elmPackages = import srcs;
15+ elmVersion = "0.19.1";
16+ inherit registryDat;
17+ };
18+
19+ installPhase = let
20+ elmfile = module:
21+ "${srcdir}/${builtins.replaceStrings [ "." ] [ "/" ] module}.elm";
22+ extension = if outputJavaScript then "js" else "html";
23+ in ''
24+ mkdir -p $out/share/doc
25+ ${lib.concatStrings (map (module: ''
26+ echo "compiling ${elmfile module}"
27+ elm make ${
28+ elmfile module
29+ } --output $out/${module}.${extension} --docs $out/share/doc/${module}.json
30+ ${lib.optionalString outputJavaScript ''
31+ echo "minifying ${elmfile module}"
32+ uglifyjs $out/${module}.${extension} --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' \
33+ | uglifyjs --mangle --output $out/${module}.min.${extension}
34+ ''}
35+ '') targets)}
36+ '';
37+ };
38+in mkDerivation {
39+ name = "frontend";
40+ srcs = ./elm-srcs.nix;
41+ src = nix-filter {
42+ root = ./.;
43+ include = [ (nix-filter.inDirectory ./frontend) ./elm.json ];
44+ };
45+ targets = [ "Main" ];
46+ srcdir = "./frontend";
47+ outputJavaScript = true;
48+}
49+
index.html+1−1
@@ -7,7 +7,7 @@
7 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
7 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
8 <link rel="stylesheet" href="vanilla/dist/style.css">
8 <link rel="stylesheet" href="vanilla/dist/style.css">
9 <link rel="stylesheet" href="style.css">
9 <link rel="stylesheet" href="style.css">
10− <title>Test.</title>
10+ <title>Warden</title>
11 <script src="elm.js"></script>
11 <script src="elm.js"></script>
12</head>
12</head>
13
13
manifest.json+1−1
@@ -9,7 +9,7 @@
9 "desktop": "warden.desktop"
9 "desktop": "warden.desktop"
10 }
10 }
11 },
11 },
12− "version": "1.2.1",
12+ "version": "1.2.4",
13 "maintainer": "Ilia Kostiuchenko <mail@iko.soy>",
13 "maintainer": "Ilia Kostiuchenko <mail@iko.soy>",
14 "framework": "@CLICK_FRAMEWORK@"
14 "framework": "@CLICK_FRAMEWORK@"
15}
15}
package-lock.jsonnew file+959
@@ -0,0 +1,959 @@
1+{
2+ "name": "warden",
3+ "lockfileVersion": 3,
4+ "requires": true,
5+ "packages": {
6+ "": {
7+ "devDependencies": {
8+ "cssnano": "^5.1.15"
9+ }
10+ },
11+ "node_modules/@trysound/sax": {
12+ "version": "0.2.0",
13+ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
14+ "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
15+ "dev": true,
16+ "engines": {
17+ "node": ">=10.13.0"
18+ }
19+ },
20+ "node_modules/boolbase": {
21+ "version": "1.0.0",
22+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
23+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
24+ "dev": true
25+ },
26+ "node_modules/browserslist": {
27+ "version": "4.21.5",
28+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
29+ "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
30+ "dev": true,
31+ "funding": [
32+ {
33+ "type": "opencollective",
34+ "url": "https://opencollective.com/browserslist"
35+ },
36+ {
37+ "type": "tidelift",
38+ "url": "https://tidelift.com/funding/github/npm/browserslist"
39+ }
40+ ],
41+ "dependencies": {
42+ "caniuse-lite": "^1.0.30001449",
43+ "electron-to-chromium": "^1.4.284",
44+ "node-releases": "^2.0.8",
45+ "update-browserslist-db": "^1.0.10"
46+ },
47+ "bin": {
48+ "browserslist": "cli.js"
49+ },
50+ "engines": {
51+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
52+ }
53+ },
54+ "node_modules/caniuse-api": {
55+ "version": "3.0.0",
56+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
57+ "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
58+ "dev": true,
59+ "dependencies": {
60+ "browserslist": "^4.0.0",
61+ "caniuse-lite": "^1.0.0",
62+ "lodash.memoize": "^4.1.2",
63+ "lodash.uniq": "^4.5.0"
64+ }
65+ },
66+ "node_modules/caniuse-lite": {
67+ "version": "1.0.30001457",
68+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz",
69+ "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==",
70+ "dev": true,
71+ "funding": [
72+ {
73+ "type": "opencollective",
74+ "url": "https://opencollective.com/browserslist"
75+ },
76+ {
77+ "type": "tidelift",
78+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
79+ }
80+ ]
81+ },
82+ "node_modules/colord": {
83+ "version": "2.9.3",
84+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
85+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
86+ "dev": true
87+ },
88+ "node_modules/commander": {
89+ "version": "7.2.0",
90+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
91+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
92+ "dev": true,
93+ "engines": {
94+ "node": ">= 10"
95+ }
96+ },
97+ "node_modules/css-declaration-sorter": {
98+ "version": "6.3.1",
99+ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz",
100+ "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==",
101+ "dev": true,
102+ "engines": {
103+ "node": "^10 || ^12 || >=14"
104+ },
105+ "peerDependencies": {
106+ "postcss": "^8.0.9"
107+ }
108+ },
109+ "node_modules/css-select": {
110+ "version": "4.3.0",
111+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
112+ "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
113+ "dev": true,
114+ "dependencies": {
115+ "boolbase": "^1.0.0",
116+ "css-what": "^6.0.1",
117+ "domhandler": "^4.3.1",
118+ "domutils": "^2.8.0",
119+ "nth-check": "^2.0.1"
120+ },
121+ "funding": {
122+ "url": "https://github.com/sponsors/fb55"
123+ }
124+ },
125+ "node_modules/css-tree": {
126+ "version": "1.1.3",
127+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
128+ "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
129+ "dev": true,
130+ "dependencies": {
131+ "mdn-data": "2.0.14",
132+ "source-map": "^0.6.1"
133+ },
134+ "engines": {
135+ "node": ">=8.0.0"
136+ }
137+ },
138+ "node_modules/css-what": {
139+ "version": "6.1.0",
140+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
141+ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
142+ "dev": true,
143+ "engines": {
144+ "node": ">= 6"
145+ },
146+ "funding": {
147+ "url": "https://github.com/sponsors/fb55"
148+ }
149+ },
150+ "node_modules/cssesc": {
151+ "version": "3.0.0",
152+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
153+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
154+ "dev": true,
155+ "bin": {
156+ "cssesc": "bin/cssesc"
157+ },
158+ "engines": {
159+ "node": ">=4"
160+ }
161+ },
162+ "node_modules/cssnano": {
163+ "version": "5.1.15",
164+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
165+ "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==",
166+ "dev": true,
167+ "dependencies": {
168+ "cssnano-preset-default": "^5.2.14",
169+ "lilconfig": "^2.0.3",
170+ "yaml": "^1.10.2"
171+ },
172+ "engines": {
173+ "node": "^10 || ^12 || >=14.0"
174+ },
175+ "funding": {
176+ "type": "opencollective",
177+ "url": "https://opencollective.com/cssnano"
178+ },
179+ "peerDependencies": {
180+ "postcss": "^8.2.15"
181+ }
182+ },
183+ "node_modules/cssnano-preset-default": {
184+ "version": "5.2.14",
185+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz",
186+ "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==",
187+ "dev": true,
188+ "dependencies": {
189+ "css-declaration-sorter": "^6.3.1",
190+ "cssnano-utils": "^3.1.0",
191+ "postcss-calc": "^8.2.3",
192+ "postcss-colormin": "^5.3.1",
193+ "postcss-convert-values": "^5.1.3",
194+ "postcss-discard-comments": "^5.1.2",
195+ "postcss-discard-duplicates": "^5.1.0",
196+ "postcss-discard-empty": "^5.1.1",
197+ "postcss-discard-overridden": "^5.1.0",
198+ "postcss-merge-longhand": "^5.1.7",
199+ "postcss-merge-rules": "^5.1.4",
200+ "postcss-minify-font-values": "^5.1.0",
201+ "postcss-minify-gradients": "^5.1.1",
202+ "postcss-minify-params": "^5.1.4",
203+ "postcss-minify-selectors": "^5.2.1",
204+ "postcss-normalize-charset": "^5.1.0",
205+ "postcss-normalize-display-values": "^5.1.0",
206+ "postcss-normalize-positions": "^5.1.1",
207+ "postcss-normalize-repeat-style": "^5.1.1",
208+ "postcss-normalize-string": "^5.1.0",
209+ "postcss-normalize-timing-functions": "^5.1.0",
210+ "postcss-normalize-unicode": "^5.1.1",
211+ "postcss-normalize-url": "^5.1.0",
212+ "postcss-normalize-whitespace": "^5.1.1",
213+ "postcss-ordered-values": "^5.1.3",
214+ "postcss-reduce-initial": "^5.1.2",
215+ "postcss-reduce-transforms": "^5.1.0",
216+ "postcss-svgo": "^5.1.0",
217+ "postcss-unique-selectors": "^5.1.1"
218+ },
219+ "engines": {
220+ "node": "^10 || ^12 || >=14.0"
221+ },
222+ "peerDependencies": {
223+ "postcss": "^8.2.15"
224+ }
225+ },
226+ "node_modules/cssnano-utils": {
227+ "version": "3.1.0",
228+ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
229+ "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
230+ "dev": true,
231+ "engines": {
232+ "node": "^10 || ^12 || >=14.0"
233+ },
234+ "peerDependencies": {
235+ "postcss": "^8.2.15"
236+ }
237+ },
238+ "node_modules/csso": {
239+ "version": "4.2.0",
240+ "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
241+ "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
242+ "dev": true,
243+ "dependencies": {
244+ "css-tree": "^1.1.2"
245+ },
246+ "engines": {
247+ "node": ">=8.0.0"
248+ }
249+ },
250+ "node_modules/dom-serializer": {
251+ "version": "1.4.1",
252+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
253+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
254+ "dev": true,
255+ "dependencies": {
256+ "domelementtype": "^2.0.1",
257+ "domhandler": "^4.2.0",
258+ "entities": "^2.0.0"
259+ },
260+ "funding": {
261+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
262+ }
263+ },
264+ "node_modules/domelementtype": {
265+ "version": "2.3.0",
266+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
267+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
268+ "dev": true,
269+ "funding": [
270+ {
271+ "type": "github",
272+ "url": "https://github.com/sponsors/fb55"
273+ }
274+ ]
275+ },
276+ "node_modules/domhandler": {
277+ "version": "4.3.1",
278+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
279+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
280+ "dev": true,
281+ "dependencies": {
282+ "domelementtype": "^2.2.0"
283+ },
284+ "engines": {
285+ "node": ">= 4"
286+ },
287+ "funding": {
288+ "url": "https://github.com/fb55/domhandler?sponsor=1"
289+ }
290+ },
291+ "node_modules/domutils": {
292+ "version": "2.8.0",
293+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
294+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
295+ "dev": true,
296+ "dependencies": {
297+ "dom-serializer": "^1.0.1",
298+ "domelementtype": "^2.2.0",
299+ "domhandler": "^4.2.0"
300+ },
301+ "funding": {
302+ "url": "https://github.com/fb55/domutils?sponsor=1"
303+ }
304+ },
305+ "node_modules/electron-to-chromium": {
306+ "version": "1.4.302",
307+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.302.tgz",
308+ "integrity": "sha512-Uk7C+7aPBryUR1Fwvk9VmipBcN9fVsqBO57jV2ZjTm+IZ6BMNqu7EDVEg2HxCNufk6QcWlFsBkhQyQroB2VWKw==",
309+ "dev": true
310+ },
311+ "node_modules/entities": {
312+ "version": "2.2.0",
313+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
314+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
315+ "dev": true,
316+ "funding": {
317+ "url": "https://github.com/fb55/entities?sponsor=1"
318+ }
319+ },
320+ "node_modules/escalade": {
321+ "version": "3.1.1",
322+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
323+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
324+ "dev": true,
325+ "engines": {
326+ "node": ">=6"
327+ }
328+ },
329+ "node_modules/lilconfig": {
330+ "version": "2.0.6",
331+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz",
332+ "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==",
333+ "dev": true,
334+ "engines": {
335+ "node": ">=10"
336+ }
337+ },
338+ "node_modules/lodash.memoize": {
339+ "version": "4.1.2",
340+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
341+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
342+ "dev": true
343+ },
344+ "node_modules/lodash.uniq": {
345+ "version": "4.5.0",
346+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
347+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
348+ "dev": true
349+ },
350+ "node_modules/mdn-data": {
351+ "version": "2.0.14",
352+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
353+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
354+ "dev": true
355+ },
356+ "node_modules/nanoid": {
357+ "version": "3.3.4",
358+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
359+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
360+ "dev": true,
361+ "peer": true,
362+ "bin": {
363+ "nanoid": "bin/nanoid.cjs"
364+ },
365+ "engines": {
366+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
367+ }
368+ },
369+ "node_modules/node-releases": {
370+ "version": "2.0.10",
371+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
372+ "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
373+ "dev": true
374+ },
375+ "node_modules/normalize-url": {
376+ "version": "6.1.0",
377+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
378+ "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
379+ "dev": true,
380+ "engines": {
381+ "node": ">=10"
382+ },
383+ "funding": {
384+ "url": "https://github.com/sponsors/sindresorhus"
385+ }
386+ },
387+ "node_modules/nth-check": {
388+ "version": "2.1.1",
389+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
390+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
391+ "dev": true,
392+ "dependencies": {
393+ "boolbase": "^1.0.0"
394+ },
395+ "funding": {
396+ "url": "https://github.com/fb55/nth-check?sponsor=1"
397+ }
398+ },
399+ "node_modules/picocolors": {
400+ "version": "1.0.0",
401+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
402+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
403+ "dev": true
404+ },
405+ "node_modules/postcss": {
406+ "version": "8.4.21",
407+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
408+ "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
409+ "dev": true,
410+ "funding": [
411+ {
412+ "type": "opencollective",
413+ "url": "https://opencollective.com/postcss/"
414+ },
415+ {
416+ "type": "tidelift",
417+ "url": "https://tidelift.com/funding/github/npm/postcss"
418+ }
419+ ],
420+ "peer": true,
421+ "dependencies": {
422+ "nanoid": "^3.3.4",
423+ "picocolors": "^1.0.0",
424+ "source-map-js": "^1.0.2"
425+ },
426+ "engines": {
427+ "node": "^10 || ^12 || >=14"
428+ }
429+ },
430+ "node_modules/postcss-calc": {
431+ "version": "8.2.4",
432+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz",
433+ "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==",
434+ "dev": true,
435+ "dependencies": {
436+ "postcss-selector-parser": "^6.0.9",
437+ "postcss-value-parser": "^4.2.0"
438+ },
439+ "peerDependencies": {
440+ "postcss": "^8.2.2"
441+ }
442+ },
443+ "node_modules/postcss-colormin": {
444+ "version": "5.3.1",
445+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz",
446+ "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==",
447+ "dev": true,
448+ "dependencies": {
449+ "browserslist": "^4.21.4",
450+ "caniuse-api": "^3.0.0",
451+ "colord": "^2.9.1",
452+ "postcss-value-parser": "^4.2.0"
453+ },
454+ "engines": {
455+ "node": "^10 || ^12 || >=14.0"
456+ },
457+ "peerDependencies": {
458+ "postcss": "^8.2.15"
459+ }
460+ },
461+ "node_modules/postcss-convert-values": {
462+ "version": "5.1.3",
463+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz",
464+ "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==",
465+ "dev": true,
466+ "dependencies": {
467+ "browserslist": "^4.21.4",
468+ "postcss-value-parser": "^4.2.0"
469+ },
470+ "engines": {
471+ "node": "^10 || ^12 || >=14.0"
472+ },
473+ "peerDependencies": {
474+ "postcss": "^8.2.15"
475+ }
476+ },
477+ "node_modules/postcss-discard-comments": {
478+ "version": "5.1.2",
479+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz",
480+ "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==",
481+ "dev": true,
482+ "engines": {
483+ "node": "^10 || ^12 || >=14.0"
484+ },
485+ "peerDependencies": {
486+ "postcss": "^8.2.15"
487+ }
488+ },
489+ "node_modules/postcss-discard-duplicates": {
490+ "version": "5.1.0",
491+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
492+ "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
493+ "dev": true,
494+ "engines": {
495+ "node": "^10 || ^12 || >=14.0"
496+ },
497+ "peerDependencies": {
498+ "postcss": "^8.2.15"
499+ }
500+ },
501+ "node_modules/postcss-discard-empty": {
502+ "version": "5.1.1",
503+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
504+ "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
505+ "dev": true,
506+ "engines": {
507+ "node": "^10 || ^12 || >=14.0"
508+ },
509+ "peerDependencies": {
510+ "postcss": "^8.2.15"
511+ }
512+ },
513+ "node_modules/postcss-discard-overridden": {
514+ "version": "5.1.0",
515+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
516+ "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
517+ "dev": true,
518+ "engines": {
519+ "node": "^10 || ^12 || >=14.0"
520+ },
521+ "peerDependencies": {
522+ "postcss": "^8.2.15"
523+ }
524+ },
525+ "node_modules/postcss-merge-longhand": {
526+ "version": "5.1.7",
527+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz",
528+ "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==",
529+ "dev": true,
530+ "dependencies": {
531+ "postcss-value-parser": "^4.2.0",
532+ "stylehacks": "^5.1.1"
533+ },
534+ "engines": {
535+ "node": "^10 || ^12 || >=14.0"
536+ },
537+ "peerDependencies": {
538+ "postcss": "^8.2.15"
539+ }
540+ },
541+ "node_modules/postcss-merge-rules": {
542+ "version": "5.1.4",
543+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz",
544+ "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==",
545+ "dev": true,
546+ "dependencies": {
547+ "browserslist": "^4.21.4",
548+ "caniuse-api": "^3.0.0",
549+ "cssnano-utils": "^3.1.0",
550+ "postcss-selector-parser": "^6.0.5"
551+ },
552+ "engines": {
553+ "node": "^10 || ^12 || >=14.0"
554+ },
555+ "peerDependencies": {
556+ "postcss": "^8.2.15"
557+ }
558+ },
559+ "node_modules/postcss-minify-font-values": {
560+ "version": "5.1.0",
561+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz",
562+ "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==",
563+ "dev": true,
564+ "dependencies": {
565+ "postcss-value-parser": "^4.2.0"
566+ },
567+ "engines": {
568+ "node": "^10 || ^12 || >=14.0"
569+ },
570+ "peerDependencies": {
571+ "postcss": "^8.2.15"
572+ }
573+ },
574+ "node_modules/postcss-minify-gradients": {
575+ "version": "5.1.1",
576+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz",
577+ "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==",
578+ "dev": true,
579+ "dependencies": {
580+ "colord": "^2.9.1",
581+ "cssnano-utils": "^3.1.0",
582+ "postcss-value-parser": "^4.2.0"
583+ },
584+ "engines": {
585+ "node": "^10 || ^12 || >=14.0"
586+ },
587+ "peerDependencies": {
588+ "postcss": "^8.2.15"
589+ }
590+ },
591+ "node_modules/postcss-minify-params": {
592+ "version": "5.1.4",
593+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz",
594+ "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==",
595+ "dev": true,
596+ "dependencies": {
597+ "browserslist": "^4.21.4",
598+ "cssnano-utils": "^3.1.0",
599+ "postcss-value-parser": "^4.2.0"
600+ },
601+ "engines": {
602+ "node": "^10 || ^12 || >=14.0"
603+ },
604+ "peerDependencies": {
605+ "postcss": "^8.2.15"
606+ }
607+ },
608+ "node_modules/postcss-minify-selectors": {
609+ "version": "5.2.1",
610+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz",
611+ "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==",
612+ "dev": true,
613+ "dependencies": {
614+ "postcss-selector-parser": "^6.0.5"
615+ },
616+ "engines": {
617+ "node": "^10 || ^12 || >=14.0"
618+ },
619+ "peerDependencies": {
620+ "postcss": "^8.2.15"
621+ }
622+ },
623+ "node_modules/postcss-normalize-charset": {
624+ "version": "5.1.0",
625+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
626+ "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
627+ "dev": true,
628+ "engines": {
629+ "node": "^10 || ^12 || >=14.0"
630+ },
631+ "peerDependencies": {
632+ "postcss": "^8.2.15"
633+ }
634+ },
635+ "node_modules/postcss-normalize-display-values": {
636+ "version": "5.1.0",
637+ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz",
638+ "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==",
639+ "dev": true,
640+ "dependencies": {
641+ "postcss-value-parser": "^4.2.0"
642+ },
643+ "engines": {
644+ "node": "^10 || ^12 || >=14.0"
645+ },
646+ "peerDependencies": {
647+ "postcss": "^8.2.15"
648+ }
649+ },
650+ "node_modules/postcss-normalize-positions": {
651+ "version": "5.1.1",
652+ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz",
653+ "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==",
654+ "dev": true,
655+ "dependencies": {
656+ "postcss-value-parser": "^4.2.0"
657+ },
658+ "engines": {
659+ "node": "^10 || ^12 || >=14.0"
660+ },
661+ "peerDependencies": {
662+ "postcss": "^8.2.15"
663+ }
664+ },
665+ "node_modules/postcss-normalize-repeat-style": {
666+ "version": "5.1.1",
667+ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz",
668+ "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==",
669+ "dev": true,
670+ "dependencies": {
671+ "postcss-value-parser": "^4.2.0"
672+ },
673+ "engines": {
674+ "node": "^10 || ^12 || >=14.0"
675+ },
676+ "peerDependencies": {
677+ "postcss": "^8.2.15"
678+ }
679+ },
680+ "node_modules/postcss-normalize-string": {
681+ "version": "5.1.0",
682+ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz",
683+ "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==",
684+ "dev": true,
685+ "dependencies": {
686+ "postcss-value-parser": "^4.2.0"
687+ },
688+ "engines": {
689+ "node": "^10 || ^12 || >=14.0"
690+ },
691+ "peerDependencies": {
692+ "postcss": "^8.2.15"
693+ }
694+ },
695+ "node_modules/postcss-normalize-timing-functions": {
696+ "version": "5.1.0",
697+ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz",
698+ "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==",
699+ "dev": true,
700+ "dependencies": {
701+ "postcss-value-parser": "^4.2.0"
702+ },
703+ "engines": {
704+ "node": "^10 || ^12 || >=14.0"
705+ },
706+ "peerDependencies": {
707+ "postcss": "^8.2.15"
708+ }
709+ },
710+ "node_modules/postcss-normalize-unicode": {
711+ "version": "5.1.1",
712+ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz",
713+ "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==",
714+ "dev": true,
715+ "dependencies": {
716+ "browserslist": "^4.21.4",
717+ "postcss-value-parser": "^4.2.0"
718+ },
719+ "engines": {
720+ "node": "^10 || ^12 || >=14.0"
721+ },
722+ "peerDependencies": {
723+ "postcss": "^8.2.15"
724+ }
725+ },
726+ "node_modules/postcss-normalize-url": {
727+ "version": "5.1.0",
728+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz",
729+ "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==",
730+ "dev": true,
731+ "dependencies": {
732+ "normalize-url": "^6.0.1",
733+ "postcss-value-parser": "^4.2.0"
734+ },
735+ "engines": {
736+ "node": "^10 || ^12 || >=14.0"
737+ },
738+ "peerDependencies": {
739+ "postcss": "^8.2.15"
740+ }
741+ },
742+ "node_modules/postcss-normalize-whitespace": {
743+ "version": "5.1.1",
744+ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz",
745+ "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==",
746+ "dev": true,
747+ "dependencies": {
748+ "postcss-value-parser": "^4.2.0"
749+ },
750+ "engines": {
751+ "node": "^10 || ^12 || >=14.0"
752+ },
753+ "peerDependencies": {
754+ "postcss": "^8.2.15"
755+ }
756+ },
757+ "node_modules/postcss-ordered-values": {
758+ "version": "5.1.3",
759+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz",
760+ "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==",
761+ "dev": true,
762+ "dependencies": {
763+ "cssnano-utils": "^3.1.0",
764+ "postcss-value-parser": "^4.2.0"
765+ },
766+ "engines": {
767+ "node": "^10 || ^12 || >=14.0"
768+ },
769+ "peerDependencies": {
770+ "postcss": "^8.2.15"
771+ }
772+ },
773+ "node_modules/postcss-reduce-initial": {
774+ "version": "5.1.2",
775+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz",
776+ "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==",
777+ "dev": true,
778+ "dependencies": {
779+ "browserslist": "^4.21.4",
780+ "caniuse-api": "^3.0.0"
781+ },
782+ "engines": {
783+ "node": "^10 || ^12 || >=14.0"
784+ },
785+ "peerDependencies": {
786+ "postcss": "^8.2.15"
787+ }
788+ },
789+ "node_modules/postcss-reduce-transforms": {
790+ "version": "5.1.0",
791+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz",
792+ "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==",
793+ "dev": true,
794+ "dependencies": {
795+ "postcss-value-parser": "^4.2.0"
796+ },
797+ "engines": {
798+ "node": "^10 || ^12 || >=14.0"
799+ },
800+ "peerDependencies": {
801+ "postcss": "^8.2.15"
802+ }
803+ },
804+ "node_modules/postcss-selector-parser": {
805+ "version": "6.0.11",
806+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
807+ "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
808+ "dev": true,
809+ "dependencies": {
810+ "cssesc": "^3.0.0",
811+ "util-deprecate": "^1.0.2"
812+ },
813+ "engines": {
814+ "node": ">=4"
815+ }
816+ },
817+ "node_modules/postcss-svgo": {
818+ "version": "5.1.0",
819+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz",
820+ "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==",
821+ "dev": true,
822+ "dependencies": {
823+ "postcss-value-parser": "^4.2.0",
824+ "svgo": "^2.7.0"
825+ },
826+ "engines": {
827+ "node": "^10 || ^12 || >=14.0"
828+ },
829+ "peerDependencies": {
830+ "postcss": "^8.2.15"
831+ }
832+ },
833+ "node_modules/postcss-unique-selectors": {
834+ "version": "5.1.1",
835+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz",
836+ "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==",
837+ "dev": true,
838+ "dependencies": {
839+ "postcss-selector-parser": "^6.0.5"
840+ },
841+ "engines": {
842+ "node": "^10 || ^12 || >=14.0"
843+ },
844+ "peerDependencies": {
845+ "postcss": "^8.2.15"
846+ }
847+ },
848+ "node_modules/postcss-value-parser": {
849+ "version": "4.2.0",
850+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
851+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
852+ "dev": true
853+ },
854+ "node_modules/source-map": {
855+ "version": "0.6.1",
856+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
857+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
858+ "dev": true,
859+ "engines": {
860+ "node": ">=0.10.0"
861+ }
862+ },
863+ "node_modules/source-map-js": {
864+ "version": "1.0.2",
865+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
866+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
867+ "dev": true,
868+ "peer": true,
869+ "engines": {
870+ "node": ">=0.10.0"
871+ }
872+ },
873+ "node_modules/stable": {
874+ "version": "0.1.8",
875+ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
876+ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
877+ "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
878+ "dev": true
879+ },
880+ "node_modules/stylehacks": {
881+ "version": "5.1.1",
882+ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
883+ "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==",
884+ "dev": true,
885+ "dependencies": {
886+ "browserslist": "^4.21.4",
887+ "postcss-selector-parser": "^6.0.4"
888+ },
889+ "engines": {
890+ "node": "^10 || ^12 || >=14.0"
891+ },
892+ "peerDependencies": {
893+ "postcss": "^8.2.15"
894+ }
895+ },
896+ "node_modules/svgo": {
897+ "version": "2.8.0",
898+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
899+ "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
900+ "dev": true,
901+ "dependencies": {
902+ "@trysound/sax": "0.2.0",
903+ "commander": "^7.2.0",
904+ "css-select": "^4.1.3",
905+ "css-tree": "^1.1.3",
906+ "csso": "^4.2.0",
907+ "picocolors": "^1.0.0",
908+ "stable": "^0.1.8"
909+ },
910+ "bin": {
911+ "svgo": "bin/svgo"
912+ },
913+ "engines": {
914+ "node": ">=10.13.0"
915+ }
916+ },
917+ "node_modules/update-browserslist-db": {
918+ "version": "1.0.10",
919+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
920+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
921+ "dev": true,
922+ "funding": [
923+ {
924+ "type": "opencollective",
925+ "url": "https://opencollective.com/browserslist"
926+ },
927+ {
928+ "type": "tidelift",
929+ "url": "https://tidelift.com/funding/github/npm/browserslist"
930+ }
931+ ],
932+ "dependencies": {
933+ "escalade": "^3.1.1",
934+ "picocolors": "^1.0.0"
935+ },
936+ "bin": {
937+ "browserslist-lint": "cli.js"
938+ },
939+ "peerDependencies": {
940+ "browserslist": ">= 4.21.0"
941+ }
942+ },
943+ "node_modules/util-deprecate": {
944+ "version": "1.0.2",
945+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
946+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
947+ "dev": true
948+ },
949+ "node_modules/yaml": {
950+ "version": "1.10.2",
951+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
952+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
953+ "dev": true,
954+ "engines": {
955+ "node": ">= 6"
956+ }
957+ }
958+ }
959+}
packages.dhall+4−4
@@ -99,8 +99,8 @@ in upstream
99-------------------------------
99-------------------------------
100-}
100-}
101let upstream =
101let upstream =
102− https://github.com/purescript/package-sets/releases/download/psc-0.15.2-20220706/packages.dhall
102+ https://github.com/purescript/package-sets/releases/download/psc-0.15.4-20220808/packages.dhall
103− sha256:7a24ebdbacb2bfa27b2fc6ce3da96f048093d64e54369965a2a7b5d9892b6031
103+ sha256:60eee64b04ca0013fae3e02a69fc3b176105c6baa2f31865c67cd5f881a412fd
104
104
105in upstream
105in upstream
106 with argonaut-aeson-generic =
106 with argonaut-aeson-generic =
@@ -125,7 +125,7 @@ in upstream
125 ]
125 ]
126 , repo =
126 , repo =
127 "https://github.com/ilyakooo0/purescript-argonaut-aeson-generic.git"
127 "https://github.com/ilyakooo0/purescript-argonaut-aeson-generic.git"
128− , version = "purescript-0.14"
128+ , version = "3e388500811ef4b6718fc776789f3be050ad7b57"
129 }
129 }
130 with untagged-union =
130 with untagged-union =
131 { dependencies =
131 { dependencies =
@@ -147,7 +147,7 @@ in upstream
147 }
147 }
148 with literals =
148 with literals =
149 { repo = "https://github.com/ilyakooo0/purescript-literals.git"
149 { repo = "https://github.com/ilyakooo0/purescript-literals.git"
150− , version = "iko/_null"
150+ , version = "6875fb28026595cfb780318305a77e79b098bb01"
151 , dependencies =
151 , dependencies =
152 [ "assert"
152 [ "assert"
153 , "effect"
153 , "effect"
registry.datnew file

Binary file not shown.

spago-packages.nixnew file+1102
@@ -0,0 +1,1102 @@
1+# This file was generated by Spago2Nix
2+
3+{ pkgs ? import <nixpkgs> {} }:
4+
5+let
6+ inputs = {
7+
8+ "aff" = pkgs.stdenv.mkDerivation {
9+ name = "aff";
10+ version = "v7.0.0";
11+ src = pkgs.fetchgit {
12+ url = "https://github.com/purescript-contrib/purescript-aff.git";
13+ rev = "2d44d9f9d0d6a416a4103fba2fb39e5160f80e36";
14+ sha256 = "1d38l16s8hvfqq5w40w21j5089svdiggkraw3rwrl6ml7lijjqx4";
15+ };
16+ phases = "installPhase";
17+ installPhase = "ln -s $src $out";
18+ };
19+
20+ "aff-promise" = pkgs.stdenv.mkDerivation {
21+ name = "aff-promise";
22+ version = "v4.0.0";
23+ src = pkgs.fetchgit {
24+ url = "https://github.com/nwolverson/purescript-aff-promise.git";
25+ rev = "3aa74e68e3e4c3e38d821375703e0b2f49d831eb";
26+ sha256 = "10gv3b05dxnlmr9zmigqs1hz4xqrx7da30aqh12kqg3zrg49k9cc";
27+ };
28+ phases = "installPhase";
29+ installPhase = "ln -s $src $out";
30+ };
31+
32+ "argonaut" = pkgs.stdenv.mkDerivation {
33+ name = "argonaut";
34+ version = "v9.0.0";
35+ src = pkgs.fetchgit {
36+ url = "https://github.com/purescript-contrib/purescript-argonaut.git";
37+ rev = "7505a47f2edb0c9cacaac4f11dcedf4723a3e9c8";
38+ sha256 = "18yxhlrwri6q858krz1klyq29fx8nvfm16c04wm2rn91mgyasn6x";
39+ };
40+ phases = "installPhase";
41+ installPhase = "ln -s $src $out";
42+ };
43+
44+ "argonaut-aeson-generic" = pkgs.stdenv.mkDerivation {
45+ name = "argonaut-aeson-generic";
46+ version = "3e388500811ef4b6718fc776789f3be050ad7b57";
47+ src = pkgs.fetchgit {
48+ url = "https://github.com/ilyakooo0/purescript-argonaut-aeson-generic.git";
49+ rev = "3e388500811ef4b6718fc776789f3be050ad7b57";
50+ sha256 = "0yhcxxz5lpgwxxsx93kmr884rk5nrvgy7lmpaixazqps2a2q0fhc";
51+ };
52+ phases = "installPhase";
53+ installPhase = "ln -s $src $out";
54+ };
55+
56+ "argonaut-codecs" = pkgs.stdenv.mkDerivation {
57+ name = "argonaut-codecs";
58+ version = "v9.0.0";
59+ src = pkgs.fetchgit {
60+ url = "https://github.com/purescript-contrib/purescript-argonaut-codecs.git";
61+ rev = "176a5dddae28fda9a2ff31ed4bf1efcc148513a4";
62+ sha256 = "08ys445222syysxh24la8bc8l20lwwqi4vdfa3ph2a60l1lx3kp8";
63+ };
64+ phases = "installPhase";
65+ installPhase = "ln -s $src $out";
66+ };
67+
68+ "argonaut-core" = pkgs.stdenv.mkDerivation {
69+ name = "argonaut-core";
70+ version = "v7.0.0";
71+ src = pkgs.fetchgit {
72+ url = "https://github.com/purescript-contrib/purescript-argonaut-core.git";
73+ rev = "68da81dd80ec36d3b013eff46dc067a972c22e5d";
74+ sha256 = "0hxl17ddbflkk0hchjgk5xj6j9fwp3b182w4g073p0dwscdl4f08";
75+ };
76+ phases = "installPhase";
77+ installPhase = "ln -s $src $out";
78+ };
79+
80+ "argonaut-generic" = pkgs.stdenv.mkDerivation {
81+ name = "argonaut-generic";
82+ version = "v8.0.0";
83+ src = pkgs.fetchgit {
84+ url = "https://github.com/purescript-contrib/purescript-argonaut-generic.git";
85+ rev = "2df4080f036762df91a24b22842e389395ef0bdd";
86+ sha256 = "0f3bkmv37nk89vscvivdr971sjydqiw7lwk9hfdfms05id8jdjkw";
87+ };
88+ phases = "installPhase";
89+ installPhase = "ln -s $src $out";
90+ };
91+
92+ "argonaut-traversals" = pkgs.stdenv.mkDerivation {
93+ name = "argonaut-traversals";
94+ version = "v10.0.0";
95+ src = pkgs.fetchgit {
96+ url = "https://github.com/purescript-contrib/purescript-argonaut-traversals.git";
97+ rev = "8d2403d8d57afb568933dbb36063d5670ce770a0";
98+ sha256 = "0v965bcl1hdp1hacbzxcm35kxxclixj0kpsdm816gs7m548z6l43";
99+ };
100+ phases = "installPhase";
101+ installPhase = "ln -s $src $out";
102+ };
103+
104+ "arraybuffer" = pkgs.stdenv.mkDerivation {
105+ name = "arraybuffer";
106+ version = "v13.0.0";
107+ src = pkgs.fetchgit {
108+ url = "https://github.com/purescript-contrib/purescript-arraybuffer.git";
109+ rev = "3b5ba3040f060057e864805546a50f319853517d";
110+ sha256 = "0cfi15r95zd7ikvs8v3pf2i3rzxjqxk7209j96d8qs6jzqlypbwd";
111+ };
112+ phases = "installPhase";
113+ installPhase = "ln -s $src $out";
114+ };
115+
116+ "arraybuffer-types" = pkgs.stdenv.mkDerivation {
117+ name = "arraybuffer-types";
118+ version = "v3.0.2";
119+ src = pkgs.fetchgit {
120+ url = "https://github.com/purescript-contrib/purescript-arraybuffer-types.git";
121+ rev = "9b0b7a0f9ee034e039f3d3a2a9c3f74eb7c9264a";
122+ sha256 = "1q3111jk6jj64bxy86lc7ik6q5mgdz87bc086wj5rm57dmlivlxx";
123+ };
124+ phases = "installPhase";
125+ installPhase = "ln -s $src $out";
126+ };
127+
128+ "arrays" = pkgs.stdenv.mkDerivation {
129+ name = "arrays";
130+ version = "v7.0.0";
131+ src = pkgs.fetchgit {
132+ url = "https://github.com/purescript/purescript-arrays.git";
133+ rev = "d20bae2f76db6cf29b7b75e26e82b8a54c32295e";
134+ sha256 = "1ciz796yrdfnqiskjjhh6r3bn9mks1dm5zin7kwzh1nfy1i4w9pz";
135+ };
136+ phases = "installPhase";
137+ installPhase = "ln -s $src $out";
138+ };
139+
140+ "assert" = pkgs.stdenv.mkDerivation {
141+ name = "assert";
142+ version = "v6.0.0";
143+ src = pkgs.fetchgit {
144+ url = "https://github.com/purescript/purescript-assert.git";
145+ rev = "27c0edb57d2ee497eb5fab664f5601c35b613eda";
146+ sha256 = "02qpcsijil64qq4kcikv2ynxl85zkryvv0vmzjm6752956ymzi0j";
147+ };
148+ phases = "installPhase";
149+ installPhase = "ln -s $src $out";
150+ };
151+
152+ "avar" = pkgs.stdenv.mkDerivation {
153+ name = "avar";
154+ version = "v5.0.0";
155+ src = pkgs.fetchgit {
156+ url = "https://github.com/purescript-contrib/purescript-avar.git";
157+ rev = "d00f5784d9cc8f079babd62740f5c52b87e5caa5";
158+ sha256 = "132g0ccmjr8328xpaycww8b5wmx1vi3li4irxxqcjk5wi47i8c9h";
159+ };
160+ phases = "installPhase";
161+ installPhase = "ln -s $src $out";
162+ };
163+
164+ "bifunctors" = pkgs.stdenv.mkDerivation {
165+ name = "bifunctors";
166+ version = "v6.0.0";
167+ src = pkgs.fetchgit {
168+ url = "https://github.com/purescript/purescript-bifunctors.git";
169+ rev = "16ba2fb6dd7f05528ebd9e2f9ca3a068b325e5b3";
170+ sha256 = "1qz5aaiq5w4g1rhjb63z47h6nqhw8hw23x1zw5alam047pq4vfkg";
171+ };
172+ phases = "installPhase";
173+ installPhase = "ln -s $src $out";
174+ };
175+
176+ "catenable-lists" = pkgs.stdenv.mkDerivation {
177+ name = "catenable-lists";
178+ version = "v7.0.0";
179+ src = pkgs.fetchgit {
180+ url = "https://github.com/purescript/purescript-catenable-lists.git";
181+ rev = "09abe1f4888bc00841ad2b59e56a9e7ce7ebd4ab";
182+ sha256 = "0fn6caspdnb0nrlj31sy7d5hxrhndfz7a2b9wfkxf5bv5vpjyawb";
183+ };
184+ phases = "installPhase";
185+ installPhase = "ln -s $src $out";
186+ };
187+
188+ "console" = pkgs.stdenv.mkDerivation {
189+ name = "console";
190+ version = "v6.0.0";
191+ src = pkgs.fetchgit {
192+ url = "https://github.com/purescript/purescript-console.git";
193+ rev = "3b83d7b792d03872afeea5e62b4f686ab0f09842";
194+ sha256 = "0fr5l1myhscp910mybp04cg6g8f2hy3ikjfc8fkqlb2dm2cqzdfs";
195+ };
196+ phases = "installPhase";
197+ installPhase = "ln -s $src $out";
198+ };
199+
200+ "const" = pkgs.stdenv.mkDerivation {
201+ name = "const";
202+ version = "v6.0.0";
203+ src = pkgs.fetchgit {
204+ url = "https://github.com/purescript/purescript-const.git";
205+ rev = "ab9570cf2b6e67f7e441178211db1231cfd75c37";
206+ sha256 = "0mcpwqqf5bcwxlzk53smvsjjz1ymlnq0ypphg6sc83ibw70g64f6";
207+ };
208+ phases = "installPhase";
209+ installPhase = "ln -s $src $out";
210+ };
211+
212+ "contravariant" = pkgs.stdenv.mkDerivation {
213+ name = "contravariant";
214+ version = "v6.0.0";
215+ src = pkgs.fetchgit {
216+ url = "https://github.com/purescript/purescript-contravariant.git";
217+ rev = "9ad3e105b8855bcc25f4e0893c784789d05a58de";
218+ sha256 = "1xkd3rfs8v20w7mj6sj6dmhfb2vb1zpmjv245xj1rahk3g16qm7m";
219+ };
220+ phases = "installPhase";
221+ installPhase = "ln -s $src $out";
222+ };
223+
224+ "control" = pkgs.stdenv.mkDerivation {
225+ name = "control";
226+ version = "v6.0.0";
227+ src = pkgs.fetchgit {
228+ url = "https://github.com/purescript/purescript-control.git";
229+ rev = "a6033808790879a17b2729e73747a9ed3fb2264e";
230+ sha256 = "05sdgywprwpav62d2bvlb80yd39brxhnmhhl1f116mm9hw5clqia";
231+ };
232+ phases = "installPhase";
233+ installPhase = "ln -s $src $out";
234+ };
235+
236+ "datetime" = pkgs.stdenv.mkDerivation {
237+ name = "datetime";
238+ version = "v6.0.0";
239+ src = pkgs.fetchgit {
240+ url = "https://github.com/purescript/purescript-datetime.git";
241+ rev = "a6a0cf1b0324964ad1854bc3377ed8766ba90e6f";
242+ sha256 = "1idjljxy8rjlw3wiypk1c9cc1fc4g9kf7drzdy6a0yjdg7504gad";
243+ };
244+ phases = "installPhase";
245+ installPhase = "ln -s $src $out";
246+ };
247+
248+ "datetime-parsing" = pkgs.stdenv.mkDerivation {
249+ name = "datetime-parsing";
250+ version = "v0.2.0";
251+ src = pkgs.fetchgit {
252+ url = "https://github.com/flounders/purescript-datetime-parsing.git";
253+ rev = "aa7d336c2681501dbe343adcbbf8f2ee51b23932";
254+ sha256 = "1w0lfs64qz1hs7zijyzpvqlp2z06wmbz4jp8cjsnw9yj46jsy8nh";
255+ };
256+ phases = "installPhase";
257+ installPhase = "ln -s $src $out";
258+ };
259+
260+ "distributive" = pkgs.stdenv.mkDerivation {
261+ name = "distributive";
262+ version = "v6.0.0";
263+ src = pkgs.fetchgit {
264+ url = "https://github.com/purescript/purescript-distributive.git";
265+ rev = "6005e513642e855ebf6f884d24a35c2803ca252a";
266+ sha256 = "0x6cfsx9ff66kvw9l10pxd5vv16r91mmfxrfc68w1xfdfi81lhdx";
267+ };
268+ phases = "installPhase";
269+ installPhase = "ln -s $src $out";
270+ };
271+
272+ "effect" = pkgs.stdenv.mkDerivation {
273+ name = "effect";
274+ version = "v4.0.0";
275+ src = pkgs.fetchgit {
276+ url = "https://github.com/purescript/purescript-effect.git";
277+ rev = "a192ddb923027d426d6ea3d8deb030c9aa7c7dda";
278+ sha256 = "0aa10lc6h9mlf4xf3g3ziig7v6kxdqvbh20kma8ay59w0b1bhmj1";
279+ };
280+ phases = "installPhase";
281+ installPhase = "ln -s $src $out";
282+ };
283+
284+ "either" = pkgs.stdenv.mkDerivation {
285+ name = "either";
286+ version = "v6.1.0";
287+ src = pkgs.fetchgit {
288+ url = "https://github.com/purescript/purescript-either.git";
289+ rev = "af655a04ed2fd694b6688af39ee20d7907ad0763";
290+ sha256 = "05zps4klvgmvlm06f4hrycssm8q0pysbqnjsrk26lfvmid6mmg63";
291+ };
292+ phases = "installPhase";
293+ installPhase = "ln -s $src $out";
294+ };
295+
296+ "enums" = pkgs.stdenv.mkDerivation {
297+ name = "enums";
298+ version = "v6.0.0";
299+ src = pkgs.fetchgit {
300+ url = "https://github.com/purescript/purescript-enums.git";
301+ rev = "bae47961d401f9acf88da38f32e87403e5f0cf2f";
302+ sha256 = "08sl5q07hv6v2008dcpg4mxiqwk9z0fhq67k0bgkxvlbsmar7khg";
303+ };
304+ phases = "installPhase";
305+ installPhase = "ln -s $src $out";
306+ };
307+
308+ "exceptions" = pkgs.stdenv.mkDerivation {
309+ name = "exceptions";
310+ version = "v6.0.0";
311+ src = pkgs.fetchgit {
312+ url = "https://github.com/purescript/purescript-exceptions.git";
313+ rev = "afab3c07c820bb49b6c5be50049db46a964a6161";
314+ sha256 = "04xrbrcjwsv8gj465ygrlqhv1majxmr6m242iazg6apxlr89hgvg";
315+ };
316+ phases = "installPhase";
317+ installPhase = "ln -s $src $out";
318+ };
319+
320+ "exists" = pkgs.stdenv.mkDerivation {
321+ name = "exists";
322+ version = "v6.0.0";
323+ src = pkgs.fetchgit {
324+ url = "https://github.com/purescript/purescript-exists.git";
325+ rev = "f765b4ace7869c27b9c05949e18c843881f9173b";
326+ sha256 = "0xnxi8fsmi15wrpq5d99gg94glk8a45hpx7pf4pmxg5r6rn1vjvx";
327+ };
328+ phases = "installPhase";
329+ installPhase = "ln -s $src $out";
330+ };
331+
332+ "float32" = pkgs.stdenv.mkDerivation {
333+ name = "float32";
334+ version = "v2.0.0";
335+ src = pkgs.fetchgit {
336+ url = "https://github.com/purescript-contrib/purescript-float32.git";
337+ rev = "3b70984d823c12c1b84a45a9b3d45199a4fcc67d";
338+ sha256 = "0a1lvga6bbhbb8g3crp3fr0kmpkzjmffhfq71ig6flin13xijgys";
339+ };
340+ phases = "installPhase";
341+ installPhase = "ln -s $src $out";
342+ };
343+
344+ "foldable-traversable" = pkgs.stdenv.mkDerivation {
345+ name = "foldable-traversable";
346+ version = "v6.0.0";
347+ src = pkgs.fetchgit {
348+ url = "https://github.com/purescript/purescript-foldable-traversable.git";
349+ rev = "b3926f870532d287ea59e2d5cd3873b81ef2a93a";
350+ sha256 = "0xg8qvyc6r9wqgy7wnw1rjqljl4wpgdrkxsm5x9rsagj2k5brxip";
351+ };
352+ phases = "installPhase";
353+ installPhase = "ln -s $src $out";
354+ };
355+
356+ "foreign" = pkgs.stdenv.mkDerivation {
357+ name = "foreign";
358+ version = "v7.0.0";
359+ src = pkgs.fetchgit {
360+ url = "https://github.com/purescript/purescript-foreign.git";
361+ rev = "2dd222d1ec7363fa0a0a7adb0d8eaf81bb7006dd";
362+ sha256 = "0ycjaal8b2rsg3zl3b7acv166vjfdvziiza3fs8nhfw0rx0xmm1m";
363+ };
364+ phases = "installPhase";
365+ installPhase = "ln -s $src $out";
366+ };
367+
368+ "foreign-object" = pkgs.stdenv.mkDerivation {
369+ name = "foreign-object";
370+ version = "v4.0.0";
371+ src = pkgs.fetchgit {
372+ url = "https://github.com/purescript/purescript-foreign-object.git";
373+ rev = "28a635827a9a6c251df73f68874070d51fe9f756";
374+ sha256 = "0ql0vgndcb5dqaqz81mvrqkrl5c2rlgxpydgdiiaxmmfxvxwi439";
375+ };
376+ phases = "installPhase";
377+ installPhase = "ln -s $src $out";
378+ };
379+
380+ "free" = pkgs.stdenv.mkDerivation {
381+ name = "free";
382+ version = "v7.0.0";
383+ src = pkgs.fetchgit {
384+ url = "https://github.com/purescript/purescript-free.git";
385+ rev = "e2d8fa8023a864363857834e11393483bced5e38";
386+ sha256 = "0gyy0k297m26gw76w7kx8k1zjczlqbqb3nmh2h4gb3r84gl05g6r";
387+ };
388+ phases = "installPhase";
389+ installPhase = "ln -s $src $out";
390+ };
391+
392+ "functions" = pkgs.stdenv.mkDerivation {
393+ name = "functions";
394+ version = "v6.0.0";
395+ src = pkgs.fetchgit {
396+ url = "https://github.com/purescript/purescript-functions.git";
397+ rev = "f626f20580483977c5b27a01aac6471e28aff367";
398+ sha256 = "1bsf2y8hx103a92yrc6m05q2dv51ckag1srd7q5n9vaf2k9byrj9";
399+ };
400+ phases = "installPhase";
401+ installPhase = "ln -s $src $out";
402+ };
403+
404+ "functors" = pkgs.stdenv.mkDerivation {
405+ name = "functors";
406+ version = "v5.0.0";
407+ src = pkgs.fetchgit {
408+ url = "https://github.com/purescript/purescript-functors.git";
409+ rev = "022ffd7a2a7ec12080314f3d217b400674a247b4";
410+ sha256 = "1pnw3r1nk0rx8mrw3ajjml40zvx9v26qrqwj77pz7hpwxigxfbff";
411+ };
412+ phases = "installPhase";
413+ installPhase = "ln -s $src $out";
414+ };
415+
416+ "gen" = pkgs.stdenv.mkDerivation {
417+ name = "gen";
418+ version = "v4.0.0";
419+ src = pkgs.fetchgit {
420+ url = "https://github.com/purescript/purescript-gen.git";
421+ rev = "9fbcc2a1261c32e30d79c5418edef4d96fe76931";
422+ sha256 = "0kajzcp9a8dmqvb3ga27hlf18m2smbp98a0bmzzb9vv156ckw0b4";
423+ };
424+ phases = "installPhase";
425+ installPhase = "ln -s $src $out";
426+ };
427+
428+ "identity" = pkgs.stdenv.mkDerivation {
429+ name = "identity";
430+ version = "v6.0.0";
431+ src = pkgs.fetchgit {
432+ url = "https://github.com/purescript/purescript-identity.git";
433+ rev = "ef6768f8a52ab0bc943a85f5761ba07c257f639f";
434+ sha256 = "1lh0pkwwdyd8q9bgf4l1m96gdnardki4r2s359cnhrwp94b43fyr";
435+ };
436+ phases = "installPhase";
437+ installPhase = "ln -s $src $out";
438+ };
439+
440+ "integers" = pkgs.stdenv.mkDerivation {
441+ name = "integers";
442+ version = "v6.0.0";
443+ src = pkgs.fetchgit {
444+ url = "https://github.com/purescript/purescript-integers.git";
445+ rev = "54d712b25c594833083d15dc9ff2418eb9c52822";
446+ sha256 = "04j9sqvkgyxxvbm8jfc2118wzmgswn8jva9fysgbsnmsg9vcxfm6";
447+ };
448+ phases = "installPhase";
449+ installPhase = "ln -s $src $out";
450+ };
451+
452+ "invariant" = pkgs.stdenv.mkDerivation {
453+ name = "invariant";
454+ version = "v6.0.0";
455+ src = pkgs.fetchgit {
456+ url = "https://github.com/purescript/purescript-invariant.git";
457+ rev = "1d2a196d51e90623adb88496c2cfd759c6736894";
458+ sha256 = "07rqag47ykdiqc5yfbc1a64ijaqliljhcw1vgbv81m7ljzzd2xna";
459+ };
460+ phases = "installPhase";
461+ installPhase = "ln -s $src $out";
462+ };
463+
464+ "js-date" = pkgs.stdenv.mkDerivation {
465+ name = "js-date";
466+ version = "v8.0.0";
467+ src = pkgs.fetchgit {
468+ url = "https://github.com/purescript-contrib/purescript-js-date.git";
469+ rev = "1ea020316946cc4b87195bca9c54d0c16abaa490";
470+ sha256 = "03535g8hc4bzyzig25hf75dls9ypsgrdk2nc45h8zw4xyy4ha0gz";
471+ };
472+ phases = "installPhase";
473+ installPhase = "ln -s $src $out";
474+ };
475+
476+ "js-timers" = pkgs.stdenv.mkDerivation {
477+ name = "js-timers";
478+ version = "v6.1.0";
479+ src = pkgs.fetchgit {
480+ url = "https://github.com/purescript-contrib/purescript-js-timers.git";
481+ rev = "7cb728b3e6dc29f355143617e6e9ac770ecd9273";
482+ sha256 = "0dm933kqhwgmpkylgrlpjplidn8biic8jlzs4l4nny4a1z20mr61";
483+ };
484+ phases = "installPhase";
485+ installPhase = "ln -s $src $out";
486+ };
487+
488+ "lazy" = pkgs.stdenv.mkDerivation {
489+ name = "lazy";
490+ version = "v6.0.0";
491+ src = pkgs.fetchgit {
492+ url = "https://github.com/purescript/purescript-lazy.git";
493+ rev = "48347841226b27af5205a1a8ec71e27a93ce86fd";
494+ sha256 = "0dxlc3b2bdqsri45i7a9bvwvv0gg43cc1gq61zi41f290a29ny2q";
495+ };
496+ phases = "installPhase";
497+ installPhase = "ln -s $src $out";
498+ };
499+
500+ "lcg" = pkgs.stdenv.mkDerivation {
501+ name = "lcg";
502+ version = "v4.0.0";
503+ src = pkgs.fetchgit {
504+ url = "https://github.com/purescript/purescript-lcg.git";
505+ rev = "67c6c6483a563a59ae036d9dca0f1be2835326a5";
506+ sha256 = "1shzn6zvc1cxd7v0bvfsk7x3xf59vxby8c5lfjvd746r6396zn65";
507+ };
508+ phases = "installPhase";
509+ installPhase = "ln -s $src $out";
510+ };
511+
512+ "lists" = pkgs.stdenv.mkDerivation {
513+ name = "lists";
514+ version = "v7.0.0";
515+ src = pkgs.fetchgit {
516+ url = "https://github.com/purescript/purescript-lists.git";
517+ rev = "b113451e5b41cad87d669a3165f955c71cd863e2";
518+ sha256 = "1mg7vy44k8jlqkri7x4ikciixx92b17wi35887x09dwdsicjf0sx";
519+ };
520+ phases = "installPhase";
521+ installPhase = "ln -s $src $out";
522+ };
523+
524+ "literals" = pkgs.stdenv.mkDerivation {
525+ name = "literals";
526+ version = "6875fb28026595cfb780318305a77e79b098bb01";
527+ src = pkgs.fetchgit {
528+ url = "https://github.com/ilyakooo0/purescript-literals.git";
529+ rev = "6875fb28026595cfb780318305a77e79b098bb01";
530+ sha256 = "0s45cdgpdhni3rj7irr8pch46yxwmdcmj2nrg1vpkvygydkikdmb";
531+ };
532+ phases = "installPhase";
533+ installPhase = "ln -s $src $out";
534+ };
535+
536+ "maybe" = pkgs.stdenv.mkDerivation {
537+ name = "maybe";
538+ version = "v6.0.0";
539+ src = pkgs.fetchgit {
540+ url = "https://github.com/purescript/purescript-maybe.git";
541+ rev = "c6f98ac1088766287106c5d9c8e30e7648d36786";
542+ sha256 = "0n33g8c579vcs06ii0r7f14jjdwzjw7p583w4nmrv9h442q2cvlz";
543+ };
544+ phases = "installPhase";
545+ installPhase = "ln -s $src $out";
546+ };
547+
548+ "media-types" = pkgs.stdenv.mkDerivation {
549+ name = "media-types";
550+ version = "v6.0.0";
551+ src = pkgs.fetchgit {
552+ url = "https://github.com/purescript-contrib/purescript-media-types.git";
553+ rev = "af853de226592f319a953637069a943dd261cba3";
554+ sha256 = "0bxpsd2yw3zg58ay649v3xld7n17n7j7n9y8l841cjih9bc7ccxx";
555+ };
556+ phases = "installPhase";
557+ installPhase = "ln -s $src $out";
558+ };
559+
560+ "newtype" = pkgs.stdenv.mkDerivation {
561+ name = "newtype";
562+ version = "v5.0.0";
563+ src = pkgs.fetchgit {
564+ url = "https://github.com/purescript/purescript-newtype.git";
565+ rev = "29d8e6dd77aec2c975c948364ec3faf26e14ee7b";
566+ sha256 = "0kfc644zn2f9rpx8fy4gjvmz04k9mv1c2xrqis8m3s0ydnhbffd7";
567+ };
568+ phases = "installPhase";
569+ installPhase = "ln -s $src $out";
570+ };
571+
572+ "nonempty" = pkgs.stdenv.mkDerivation {
573+ name = "nonempty";
574+ version = "v7.0.0";
575+ src = pkgs.fetchgit {
576+ url = "https://github.com/purescript/purescript-nonempty.git";
577+ rev = "28150ecc7419238b187abd609a92a645273348bb";
578+ sha256 = "1mwdc2sny2ygp67kyk7h2493vq7syf7j18s3d9a5gwf1y7jlf7gh";
579+ };
580+ phases = "installPhase";
581+ installPhase = "ln -s $src $out";
582+ };
583+
584+ "now" = pkgs.stdenv.mkDerivation {
585+ name = "now";
586+ version = "v6.0.0";
587+ src = pkgs.fetchgit {
588+ url = "https://github.com/purescript-contrib/purescript-now.git";
589+ rev = "b5ffed2381e5fefc063f484e607e8499e79eaf32";
590+ sha256 = "01khmqs4iz7dhlvd43zxj19q0c0vvqf1m128vgvgxz5mv430zfgr";
591+ };
592+ phases = "installPhase";
593+ installPhase = "ln -s $src $out";
594+ };
595+
596+ "nullable" = pkgs.stdenv.mkDerivation {
597+ name = "nullable";
598+ version = "v6.0.0";
599+ src = pkgs.fetchgit {
600+ url = "https://github.com/purescript-contrib/purescript-nullable.git";
601+ rev = "3202744c6c65e8d1fbba7f4256a1c482078e7fb5";
602+ sha256 = "10s3b54pjmr2rxlyzvc8yc99k1dpn0qrijnc4y65yj5z6bxf2791";
603+ };
604+ phases = "installPhase";
605+ installPhase = "ln -s $src $out";
606+ };
607+
608+ "numbers" = pkgs.stdenv.mkDerivation {
609+ name = "numbers";
610+ version = "v9.0.0";
611+ src = pkgs.fetchgit {
612+ url = "https://github.com/purescript/purescript-numbers.git";
613+ rev = "2a53528f18f9415334bae28e7bb3cf3be86342c2";
614+ sha256 = "1h4v6ir1hq6gvkk0kla38vlcd6bv73xkc8pv71jygwqxrdwfxxgw";
615+ };
616+ phases = "installPhase";
617+ installPhase = "ln -s $src $out";
618+ };
619+
620+ "ordered-collections" = pkgs.stdenv.mkDerivation {
621+ name = "ordered-collections";
622+ version = "v3.0.0";
623+ src = pkgs.fetchgit {
624+ url = "https://github.com/purescript/purescript-ordered-collections.git";
625+ rev = "9826b7632d0d0a691173bde308a634195f42a419";
626+ sha256 = "1wk8mcn1zsxi0yk9ybas2v7m0drb492806gld1xxxic8x1i19ws0";
627+ };
628+ phases = "installPhase";
629+ installPhase = "ln -s $src $out";
630+ };
631+
632+ "orders" = pkgs.stdenv.mkDerivation {
633+ name = "orders";
634+ version = "v6.0.0";
635+ src = pkgs.fetchgit {
636+ url = "https://github.com/purescript/purescript-orders.git";
637+ rev = "f86db621ec5eef1274145f8b1fd8ebbfe0ed4a2c";
638+ sha256 = "14fjls3v14ia6fr2w4p0i5dqv10zk343wg28m4c77a17jmvbs9r4";
639+ };
640+ phases = "installPhase";
641+ installPhase = "ln -s $src $out";
642+ };
643+
644+ "parallel" = pkgs.stdenv.mkDerivation {
645+ name = "parallel";
646+ version = "v6.0.0";
647+ src = pkgs.fetchgit {
648+ url = "https://github.com/purescript/purescript-parallel.git";
649+ rev = "85290dca837771ac4870071008c933d315ef678f";
650+ sha256 = "0bpwvzq4dn7vx5mfj12w1zvvnamc6w2c45c2v54b9yw36snnwpcf";
651+ };
652+ phases = "installPhase";
653+ installPhase = "ln -s $src $out";
654+ };
655+
656+ "parsing" = pkgs.stdenv.mkDerivation {
657+ name = "parsing";
658+ version = "v9.1.0";
659+ src = pkgs.fetchgit {
660+ url = "https://github.com/purescript-contrib/purescript-parsing.git";
661+ rev = "44ef16b7cfb7cedc3d518c00ef10c6cb73ff4fc8";
662+ sha256 = "1wkk3p1w2k1cvby4airyxgavk1djfzvzc2ch6b8951b592rj8lkr";
663+ };
664+ phases = "installPhase";
665+ installPhase = "ln -s $src $out";
666+ };
667+
668+ "partial" = pkgs.stdenv.mkDerivation {
669+ name = "partial";
670+ version = "v4.0.0";
671+ src = pkgs.fetchgit {
672+ url = "https://github.com/purescript/purescript-partial.git";
673+ rev = "0fa0646f5ea1ec5f0c46dcbd770c705a6c9ad3ec";
674+ sha256 = "04s1h0r3slyd8kcamhqqrr6piksl9y76nmf2418j0ifhp16qwxmm";
675+ };
676+ phases = "installPhase";
677+ installPhase = "ln -s $src $out";
678+ };
679+
680+ "prelude" = pkgs.stdenv.mkDerivation {
681+ name = "prelude";
682+ version = "v6.0.0";
683+ src = pkgs.fetchgit {
684+ url = "https://github.com/purescript/purescript-prelude.git";
685+ rev = "32787f4399c92459c41602131a5858559eb868c5";
686+ sha256 = "0jkbckxw2640gmfi2f8bpf2zwnay2dxy8n24rvxl3w3dihcgd9qc";
687+ };
688+ phases = "installPhase";
689+ installPhase = "ln -s $src $out";
690+ };
691+
692+ "profunctor" = pkgs.stdenv.mkDerivation {
693+ name = "profunctor";
694+ version = "v6.0.0";
695+ src = pkgs.fetchgit {
696+ url = "https://github.com/purescript/purescript-profunctor.git";
697+ rev = "0a966a14e7b0c827d44657dc1710cdc712d2e034";
698+ sha256 = "07rhk8micbc74my6s53xbj2smvvwah2w1drqrcmcnncxdks3lqg3";
699+ };
700+ phases = "installPhase";
701+ installPhase = "ln -s $src $out";
702+ };
703+
704+ "profunctor-lenses" = pkgs.stdenv.mkDerivation {
705+ name = "profunctor-lenses";
706+ version = "v8.0.0";
707+ src = pkgs.fetchgit {
708+ url = "https://github.com/purescript-contrib/purescript-profunctor-lenses.git";
709+ rev = "973d567afe458fd802cf4f0d9725b6dc35ad9297";
710+ sha256 = "0axz7nznn12iqh6sn9qjg6i8qglpdsqgkp30ndwdj98czcnbnybv";
711+ };
712+ phases = "installPhase";
713+ installPhase = "ln -s $src $out";
714+ };
715+
716+ "psci-support" = pkgs.stdenv.mkDerivation {
717+ name = "psci-support";
718+ version = "v6.0.0";
719+ src = pkgs.fetchgit {
720+ url = "https://github.com/purescript/purescript-psci-support.git";
721+ rev = "897cdb543548cb6078d69b6413b54841404eda72";
722+ sha256 = "1ix53r8avkn3fw72mngwzw7v6c6mv7j4miw5mrgjrh9hb8p2ydl1";
723+ };
724+ phases = "installPhase";
725+ installPhase = "ln -s $src $out";
726+ };
727+
728+ "quickcheck" = pkgs.stdenv.mkDerivation {
729+ name = "quickcheck";
730+ version = "v8.0.1";
731+ src = pkgs.fetchgit {
732+ url = "https://github.com/purescript/purescript-quickcheck.git";
733+ rev = "bf5029f97e6c0d7552d3a08d2ab793a19e2c5e3d";
734+ sha256 = "142dvh57fl8b6i7mm37a38v7vkc1znbqz6l6wqa704m53hkikvyd";
735+ };
736+ phases = "installPhase";
737+ installPhase = "ln -s $src $out";
738+ };
739+
740+ "random" = pkgs.stdenv.mkDerivation {
741+ name = "random";
742+ version = "v6.0.0";
743+ src = pkgs.fetchgit {
744+ url = "https://github.com/purescript/purescript-random.git";
745+ rev = "9540bc965a9596da02fefd9949418bb19c92533a";
746+ sha256 = "0qz14qviz5053j9h1jwpk0gnn692hcdx6fp90wckzrnw31d53174";
747+ };
748+ phases = "installPhase";
749+ installPhase = "ln -s $src $out";
750+ };
751+
752+ "record" = pkgs.stdenv.mkDerivation {
753+ name = "record";
754+ version = "v4.0.0";
755+ src = pkgs.fetchgit {
756+ url = "https://github.com/purescript/purescript-record.git";
757+ rev = "c89cd1ada6b636692571fc374196b1c39c4c9f70";
758+ sha256 = "1g7s2h1as5cz824wpm0jhjprrh66shha5i4gq37q73yw0s5p2ahm";
759+ };
760+ phases = "installPhase";
761+ installPhase = "ln -s $src $out";
762+ };
763+
764+ "refs" = pkgs.stdenv.mkDerivation {
765+ name = "refs";
766+ version = "v6.0.0";
767+ src = pkgs.fetchgit {
768+ url = "https://github.com/purescript/purescript-refs.git";
769+ rev = "f8e6216da4cb9309fde1f20cd6f69ac3a3b7f9e8";
770+ sha256 = "09bvfxhjfwfwv55py45s71maazwrr68k0rk4v8ynfqv91h34319h";
771+ };
772+ phases = "installPhase";
773+ installPhase = "ln -s $src $out";
774+ };
775+
776+ "run" = pkgs.stdenv.mkDerivation {
777+ name = "run";
778+ version = "v5.0.0";
779+ src = pkgs.fetchgit {
780+ url = "https://github.com/natefaubion/purescript-run.git";
781+ rev = "abec7c343e92154d44b9dafd52b91ee82d32a870";
782+ sha256 = "059xhjxjfs1w2hmgld53kciyfws3pmjyz75w836ph99rqr4aczny";
783+ };
784+ phases = "installPhase";
785+ installPhase = "ln -s $src $out";
786+ };
787+
788+ "safe-coerce" = pkgs.stdenv.mkDerivation {
789+ name = "safe-coerce";
790+ version = "v2.0.0";
791+ src = pkgs.fetchgit {
792+ url = "https://github.com/purescript/purescript-safe-coerce.git";
793+ rev = "7fa799ae80a38b8d948efcb52608e58e198b3da7";
794+ sha256 = "00m4l733gpl0153cbl6n5kly7jr8ids399apza2rbczif40brp9g";
795+ };
796+ phases = "installPhase";
797+ installPhase = "ln -s $src $out";
798+ };
799+
800+ "st" = pkgs.stdenv.mkDerivation {
801+ name = "st";
802+ version = "v6.0.0";
803+ src = pkgs.fetchgit {
804+ url = "https://github.com/purescript/purescript-st.git";
805+ rev = "2cc7ae1c3318a303378c4a9f3fa0f10ee7cc3589";
806+ sha256 = "1ykk27zn03svfsv2s1mf88d6x3q6qhb9bwjzgals79krw8w0aiyl";
807+ };
808+ phases = "installPhase";
809+ installPhase = "ln -s $src $out";
810+ };
811+
812+ "strings" = pkgs.stdenv.mkDerivation {
813+ name = "strings";
814+ version = "v6.0.0";
815+ src = pkgs.fetchgit {
816+ url = "https://github.com/purescript/purescript-strings.git";
817+ rev = "4bc6954448d056f8aa7a659695a6ad60ad4fdf19";
818+ sha256 = "101va3rawcn5inp20krfg192bbjbvm27xfzwwc1inb2ya0m98amg";
819+ };
820+ phases = "installPhase";
821+ installPhase = "ln -s $src $out";
822+ };
823+
824+ "tailrec" = pkgs.stdenv.mkDerivation {
825+ name = "tailrec";
826+ version = "v6.0.0";
827+ src = pkgs.fetchgit {
828+ url = "https://github.com/purescript/purescript-tailrec.git";
829+ rev = "5e2104aa734b31a17074cc805bf087d72b65afd1";
830+ sha256 = "0vc3dpsd2xxz694zlm75nx1cn6c6f29nzkb8xlxkk6ydw3wpsk3w";
831+ };
832+ phases = "installPhase";
833+ installPhase = "ln -s $src $out";
834+ };
835+
836+ "test-unit" = pkgs.stdenv.mkDerivation {
837+ name = "test-unit";
838+ version = "v17.0.0";
839+ src = pkgs.fetchgit {
840+ url = "https://github.com/bodil/purescript-test-unit.git";
841+ rev = "3112d7ebe06d467238058a6384dc75ffd960d335";
842+ sha256 = "02gfb4dqbj5v7dwifm8jhr0lh7lfp5hari5795w1z48wy3apnvvx";
843+ };
844+ phases = "installPhase";
845+ installPhase = "ln -s $src $out";
846+ };
847+
848+ "transformers" = pkgs.stdenv.mkDerivation {
849+ name = "transformers";
850+ version = "v6.0.0";
851+ src = pkgs.fetchgit {
852+ url = "https://github.com/purescript/purescript-transformers.git";
853+ rev = "be72ab52357d9a665cbf93d73ba1c07c4b0957ee";
854+ sha256 = "0ijrdsppl8vx0rlbwc9p0vjbmvwlcy4ia7xymvk6y34zbxzjlzm6";
855+ };
856+ phases = "installPhase";
857+ installPhase = "ln -s $src $out";
858+ };
859+
860+ "tuples" = pkgs.stdenv.mkDerivation {
861+ name = "tuples";
862+ version = "v7.0.0";
863+ src = pkgs.fetchgit {
864+ url = "https://github.com/purescript/purescript-tuples.git";
865+ rev = "4f52da2729b448c8564369378f1232d8d2dc1d8b";
866+ sha256 = "1m1ng0xxicb73945jymcl1hn2y2hmynlnmhb2k0kkn1jrjwgcc3d";
867+ };
868+ phases = "installPhase";
869+ installPhase = "ln -s $src $out";
870+ };
871+
872+ "type-equality" = pkgs.stdenv.mkDerivation {
873+ name = "type-equality";
874+ version = "v4.0.1";
875+ src = pkgs.fetchgit {
876+ url = "https://github.com/purescript/purescript-type-equality.git";
877+ rev = "0525b7d39e0fbd81b4209518139fb8ab02695774";
878+ sha256 = "1ass38jdycsjisdimdc4drg2w8vkkwp6lkvz3kvy7q0h98vdmlbr";
879+ };
880+ phases = "installPhase";
881+ installPhase = "ln -s $src $out";
882+ };
883+
884+ "typelevel-prelude" = pkgs.stdenv.mkDerivation {
885+ name = "typelevel-prelude";
886+ version = "v7.0.0";
887+ src = pkgs.fetchgit {
888+ url = "https://github.com/purescript/purescript-typelevel-prelude.git";
889+ rev = "dca2fe3c8cfd5527d4fe70c4bedfda30148405bf";
890+ sha256 = "0x86mrg33kpnrnsfp4p3c92j5lpyqzy87bxdynwf7smk3inqr2jc";
891+ };
892+ phases = "installPhase";
893+ installPhase = "ln -s $src $out";
894+ };
895+
896+ "uint" = pkgs.stdenv.mkDerivation {
897+ name = "uint";
898+ version = "v7.0.0";
899+ src = pkgs.fetchgit {
900+ url = "https://github.com/purescript-contrib/purescript-uint.git";
901+ rev = "9e4f76ffd5192472f75583844172fe8ab3c0cb9f";
902+ sha256 = "173bhrd006q53s7agwyasxhfbr89x9jpz5b47vm2fr74l3jcw3lq";
903+ };
904+ phases = "installPhase";
905+ installPhase = "ln -s $src $out";
906+ };
907+
908+ "undefined-is-not-a-problem" = pkgs.stdenv.mkDerivation {
909+ name = "undefined-is-not-a-problem";
910+ version = "v1.1.0";
911+ src = pkgs.fetchgit {
912+ url = "https://github.com/paluh/purescript-undefined-is-not-a-problem.git";
913+ rev = "8ac77ac8525343f7319cd48bf2ceb736286f3b27";
914+ sha256 = "1qv7gdyslfj86ga0a7gxkbpvykm3s1x4kzcm8zi75lhlvkpyjh3w";
915+ };
916+ phases = "installPhase";
917+ installPhase = "ln -s $src $out";
918+ };
919+
920+ "unfoldable" = pkgs.stdenv.mkDerivation {
921+ name = "unfoldable";
922+ version = "v6.0.0";
923+ src = pkgs.fetchgit {
924+ url = "https://github.com/purescript/purescript-unfoldable.git";
925+ rev = "493dfe04ed590e20d8f69079df2f58486882748d";
926+ sha256 = "15z2k639ph8wdkrc2y838m5am1z7szw2vqymmv021skzisyn7zwf";
927+ };
928+ phases = "installPhase";
929+ installPhase = "ln -s $src $out";
930+ };
931+
932+ "unicode" = pkgs.stdenv.mkDerivation {
933+ name = "unicode";
934+ version = "v6.0.0";
935+ src = pkgs.fetchgit {
936+ url = "https://github.com/purescript-contrib/purescript-unicode.git";
937+ rev = "6454d59d9e1fd1bc5a72e80e985d8282022a567a";
938+ sha256 = "0w2gsmqcy7pj5vd22qzpig20bdgzmbagyqxrg9mm1njjfsmcm8cv";
939+ };
940+ phases = "installPhase";
941+ installPhase = "ln -s $src $out";
942+ };
943+
944+ "unsafe-coerce" = pkgs.stdenv.mkDerivation {
945+ name = "unsafe-coerce";
946+ version = "v6.0.0";
947+ src = pkgs.fetchgit {
948+ url = "https://github.com/purescript/purescript-unsafe-coerce.git";
949+ rev = "ab956f82e66e633f647fb3098e8ddd3ec58d689f";
950+ sha256 = "0r6d3dx8jalfzvrvkagz9v05yxwkkhgbzlpswg4w1cyl03zjcla4";
951+ };
952+ phases = "installPhase";
953+ installPhase = "ln -s $src $out";
954+ };
955+
956+ "untagged-union" = pkgs.stdenv.mkDerivation {
957+ name = "untagged-union";
958+ version = "6c5bccef38696a16e86ba9a65cf778b4462c4a66";
959+ src = pkgs.fetchgit {
960+ url = "https://github.com/rowtype-yoga/purescript-untagged-union.git";
961+ rev = "6c5bccef38696a16e86ba9a65cf778b4462c4a66";
962+ sha256 = "0s4pik6xcr7zqhlrjxjqgzp8hfg09kgd58zq3xjj0inw9ly35ywn";
963+ };
964+ phases = "installPhase";
965+ installPhase = "ln -s $src $out";
966+ };
967+
968+ "variant" = pkgs.stdenv.mkDerivation {
969+ name = "variant";
970+ version = "v8.0.0";
971+ src = pkgs.fetchgit {
972+ url = "https://github.com/natefaubion/purescript-variant.git";
973+ rev = "8b2bd73a4202257d80a955c4dd36f6055f149823";
974+ sha256 = "18nyxnaqqg1zzydwd2hh9hbzr31j509g5yb1lnd0m60bma4l9h5g";
975+ };
976+ phases = "installPhase";
977+ installPhase = "ln -s $src $out";
978+ };
979+
980+ "web-dom" = pkgs.stdenv.mkDerivation {
981+ name = "web-dom";
982+ version = "v6.0.0";
983+ src = pkgs.fetchgit {
984+ url = "https://github.com/purescript-web/purescript-web-dom.git";
985+ rev = "568a1ee158b29e6e739e7a9aaed3e35ca4c4305a";
986+ sha256 = "0angs86ld0h3ld889ag55lh62101dfn3fknyqrfv0imgn40vwm44";
987+ };
988+ phases = "installPhase";
989+ installPhase = "ln -s $src $out";
990+ };
991+
992+ "web-events" = pkgs.stdenv.mkDerivation {
993+ name = "web-events";
994+ version = "v4.0.0";
995+ src = pkgs.fetchgit {
996+ url = "https://github.com/purescript-web/purescript-web-events.git";
997+ rev = "2124356117be7b764a2f3948032255ac4dab7051";
998+ sha256 = "0l47gsgj71x0gjbhjqwsar2y44ljhq3xa0nkgr1qvqxmcm00llqf";
999+ };
1000+ phases = "installPhase";
1001+ installPhase = "ln -s $src $out";
1002+ };
1003+
1004+ "web-file" = pkgs.stdenv.mkDerivation {
1005+ name = "web-file";
1006+ version = "v4.0.0";
1007+ src = pkgs.fetchgit {
1008+ url = "https://github.com/purescript-web/purescript-web-file.git";
1009+ rev = "023786ae62bbb8bf58156dd7f02011fa38221ef1";
1010+ sha256 = "1wjf1m5y2qsba83is297icv9zyl7jilxdga0192mm1rp0j16jjln";
1011+ };
1012+ phases = "installPhase";
1013+ installPhase = "ln -s $src $out";
1014+ };
1015+
1016+ "web-html" = pkgs.stdenv.mkDerivation {
1017+ name = "web-html";
1018+ version = "v4.0.0";
1019+ src = pkgs.fetchgit {
1020+ url = "https://github.com/purescript-web/purescript-web-html.git";
1021+ rev = "be189cf91b9a19cf493637423522e2fe4a0088cc";
1022+ sha256 = "0yspv6sci3mkflvqwf5jvz3a8nclmhbvazx9n34acyj3aai7k6bs";
1023+ };
1024+ phases = "installPhase";
1025+ installPhase = "ln -s $src $out";
1026+ };
1027+
1028+ "web-storage" = pkgs.stdenv.mkDerivation {
1029+ name = "web-storage";
1030+ version = "v5.0.0";
1031+ src = pkgs.fetchgit {
1032+ url = "https://github.com/purescript-web/purescript-web-storage.git";
1033+ rev = "6b74461e136755db70c271dc898d51776363d7e2";
1034+ sha256 = "0q1grh8cp6h1szsqg3xmwlzrc1bbz8yzlwxlcl1iym5mjiyzgkcs";
1035+ };
1036+ phases = "installPhase";
1037+ installPhase = "ln -s $src $out";
1038+ };
1039+
1040+ };
1041+
1042+ cpPackage = pkg:
1043+ let
1044+ target = ".spago/${pkg.name}/${pkg.version}";
1045+ in ''
1046+ if [ ! -e ${target} ]; then
1047+ echo "Installing ${target}."
1048+ mkdir -p ${target}
1049+ cp --no-preserve=mode,ownership,timestamp -r ${toString pkg.outPath}/* ${target}
1050+ else
1051+ echo "${target} already exists. Skipping."
1052+ fi
1053+ '';
1054+
1055+ getGlob = pkg: ''".spago/${pkg.name}/${pkg.version}/src/**/*.purs"'';
1056+
1057+ getStoreGlob = pkg: ''"${pkg.outPath}/src/**/*.purs"'';
1058+
1059+in {
1060+ inherit inputs;
1061+
1062+ installSpagoStyle = pkgs.writeShellScriptBin "install-spago-style" ''
1063+ set -e
1064+ echo installing dependencies...
1065+ ${builtins.toString (builtins.map cpPackage (builtins.attrValues inputs))}
1066+ echo "echo done."
1067+ '';
1068+
1069+ buildSpagoStyle = pkgs.writeShellScriptBin "build-spago-style" ''
1070+ set -e
1071+ echo building project...
1072+ purs compile ${builtins.toString (builtins.map getGlob (builtins.attrValues inputs))} "$@"
1073+ echo done.
1074+ '';
1075+
1076+ buildFromNixStore = pkgs.writeShellScriptBin "build-from-store" ''
1077+ set -e
1078+ echo building project using sources from nix store...
1079+ purs compile ${builtins.toString (
1080+ builtins.map getStoreGlob (builtins.attrValues inputs))} "$@"
1081+ echo done.
1082+ '';
1083+
1084+ mkBuildProjectOutput =
1085+ { src, purs }:
1086+
1087+ pkgs.stdenv.mkDerivation {
1088+ name = "build-project-output";
1089+ src = src;
1090+
1091+ buildInputs = [ purs ];
1092+
1093+ installPhase = ''
1094+ mkdir -p $out
1095+ purs compile "$src/**/*.purs" ${builtins.toString
1096+ (builtins.map
1097+ (x: ''"${x.outPath}/src/**/*.purs"'')
1098+ (builtins.attrValues inputs))}
1099+ mv output $out
1100+ '';
1101+ };
1102+}
spago.dhall+2
@@ -35,8 +35,10 @@ to generate this file without the comments in this block.
35 , "maybe"
35 , "maybe"
36 , "newtype"
36 , "newtype"
37 , "nullable"
37 , "nullable"
38+ , "numbers"
38 , "orders"
39 , "orders"
39 , "prelude"
40 , "prelude"
41+ , "random"
40 , "refs"
42 , "refs"
41 , "run"
43 , "run"
42 , "strings"
44 , "strings"
tests/src/test.spec.ts+2−2
@@ -85,7 +85,7 @@ async function screenshot(page: Page) {
85 await page.locator('.p-icon--spinner.u-animation--spin.spinner').waitFor({ state: "hidden" })
85 await page.locator('.p-icon--spinner.u-animation--spin.spinner').waitFor({ state: "hidden" })
86 await screenshot(page)
86 await screenshot(page)
87 } else {
87 } else {
88− await expect.soft(page).toHaveScreenshot({ animations: "disabled", fullPage: true })
88+ await expect.soft(page).toHaveScreenshot({ animations: "disabled", fullPage: true, maxDiffPixelRatio: 0.01 })
89 }
89 }
90}
90}
91
91
@@ -108,7 +108,7 @@ function cipherPage(name: string) {
108}
108}
109
109
110test.beforeEach(async ({ page }) => {
110test.beforeEach(async ({ page }) => {
111− await page.goto(`file://${__dirname}/../../build/all/app/install/index.html`);
111+ await page.goto(`file://${__dirname}/../../dist/index.html`);
112 await page.addStyleTag({ content: '.hide-in-test {opacity: 0;}' })
112 await page.addStyleTag({ content: '.hide-in-test {opacity: 0;}' })
113})
113})
114
114
tests/src/test.spec.ts-snapshots/Card-cipher-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Cards-view-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Contact-cipher-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Contacts-view-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Create-Card-entry-page-2-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Create-Contact-entry-page-2-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Create-Note-entry-page-2-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Empty-ciphers-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Filled-ciphers-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Login-cipher-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Login-entry-page-2-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Login-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Note-cipher-page-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Notes-view-1-Pixel-3-linux.png

Binary file not shown.

tests/src/test.spec.ts-snapshots/Passwords-view-1-Pixel-3-linux.png

Binary file not shown.

vanilladeleted−1

Submodule changed.

warden.apparmor+1−1
@@ -5,5 +5,5 @@
5 "audio",
5 "audio",
6 "networking"
6 "networking"
7 ],
7 ],
8− "policy_version": 16.04
8+ "policy_version": 20.04
9}
9}