enable/disable e2e encryption
This commit is contained in:
167
package-lock.json
generated
167
package-lock.json
generated
@@ -29,9 +29,11 @@
|
|||||||
"daisyui": "^2.51.6",
|
"daisyui": "^2.51.6",
|
||||||
"date-fns": "^2.29.3",
|
"date-fns": "^2.29.3",
|
||||||
"dompurify": "^3.0.2",
|
"dompurify": "^3.0.2",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"firebase": "^9.22.0",
|
"firebase": "^9.22.0",
|
||||||
"firebaseui": "^6.0.2",
|
"firebaseui": "^6.0.2",
|
||||||
"hamburgers": "^1.2.1",
|
"hamburgers": "^1.2.1",
|
||||||
|
"jszip": "^3.10.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"marked": "^4.3.0",
|
"marked": "^4.3.0",
|
||||||
"shortid": "^2.2.16",
|
"shortid": "^2.2.16",
|
||||||
@@ -45,6 +47,7 @@
|
|||||||
"@tsconfig/node18": "^2.0.1",
|
"@tsconfig/node18": "^2.0.1",
|
||||||
"@types/crypto-js": "^4.1.1",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/dompurify": "^3.0.2",
|
"@types/dompurify": "^3.0.2",
|
||||||
|
"@types/file-saver": "^2.0.5",
|
||||||
"@types/lodash-es": "^4.17.7",
|
"@types/lodash-es": "^4.17.7",
|
||||||
"@types/node": "^20.2.1",
|
"@types/node": "^20.2.1",
|
||||||
"@types/shortid": "^0.0.29",
|
"@types/shortid": "^0.0.29",
|
||||||
@@ -2069,6 +2072,12 @@
|
|||||||
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/glob": {
|
"node_modules/@types/glob": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
||||||
@@ -4224,8 +4233,7 @@
|
|||||||
"node_modules/core-util-is": {
|
"node_modules/core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/cors": {
|
"node_modules/cors": {
|
||||||
"version": "2.8.5",
|
"version": "2.8.5",
|
||||||
@@ -5664,6 +5672,11 @@
|
|||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": "^10.12.0 || >=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||||
|
},
|
||||||
"node_modules/file-uri-to-path": {
|
"node_modules/file-uri-to-path": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
|
||||||
@@ -7028,6 +7041,11 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
||||||
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
|
||||||
@@ -7578,8 +7596,7 @@
|
|||||||
"node_modules/isarray": {
|
"node_modules/isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/isexe": {
|
"node_modules/isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -7839,6 +7856,44 @@
|
|||||||
"node": ">=0.6.0"
|
"node": ">=0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jszip": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"lie": "~3.3.0",
|
||||||
|
"pako": "~1.0.2",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"node_modules/jszip/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jwa": {
|
"node_modules/jwa": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
||||||
@@ -7954,6 +8009,14 @@
|
|||||||
"libsodium": "^0.7.11"
|
"libsodium": "^0.7.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lie": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
@@ -9358,6 +9421,11 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -9825,8 +9893,7 @@
|
|||||||
"node_modules/process-nextick-args": {
|
"node_modules/process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/progress": {
|
"node_modules/progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
@@ -10733,6 +10800,11 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||||
|
},
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
@@ -13980,6 +14052,12 @@
|
|||||||
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/glob": {
|
"@types/glob": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz",
|
||||||
@@ -15606,8 +15684,7 @@
|
|||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"cors": {
|
"cors": {
|
||||||
"version": "2.8.5",
|
"version": "2.8.5",
|
||||||
@@ -16740,6 +16817,11 @@
|
|||||||
"flat-cache": "^3.0.4"
|
"flat-cache": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||||
|
},
|
||||||
"file-uri-to-path": {
|
"file-uri-to-path": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
|
||||||
@@ -17806,6 +17888,11 @@
|
|||||||
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
|
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
||||||
|
},
|
||||||
"immutable": {
|
"immutable": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
|
||||||
@@ -18196,8 +18283,7 @@
|
|||||||
"isarray": {
|
"isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"isexe": {
|
"isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -18427,6 +18513,46 @@
|
|||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jszip": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||||
|
"requires": {
|
||||||
|
"lie": "~3.3.0",
|
||||||
|
"pako": "~1.0.2",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "^1.0.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jwa": {
|
"jwa": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
||||||
@@ -18535,6 +18661,14 @@
|
|||||||
"libsodium": "^0.7.11"
|
"libsodium": "^0.7.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lie": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||||
|
"requires": {
|
||||||
|
"immediate": "~3.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lilconfig": {
|
"lilconfig": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
@@ -19606,6 +19740,11 @@
|
|||||||
"netmask": "^2.0.2"
|
"netmask": "^2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pako": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||||
|
},
|
||||||
"parent-module": {
|
"parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -19861,8 +20000,7 @@
|
|||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"progress": {
|
"progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
@@ -20570,6 +20708,11 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||||
|
},
|
||||||
"setprototypeof": {
|
"setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
|
|||||||
@@ -36,9 +36,11 @@
|
|||||||
"daisyui": "^2.51.6",
|
"daisyui": "^2.51.6",
|
||||||
"date-fns": "^2.29.3",
|
"date-fns": "^2.29.3",
|
||||||
"dompurify": "^3.0.2",
|
"dompurify": "^3.0.2",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"firebase": "^9.22.0",
|
"firebase": "^9.22.0",
|
||||||
"firebaseui": "^6.0.2",
|
"firebaseui": "^6.0.2",
|
||||||
"hamburgers": "^1.2.1",
|
"hamburgers": "^1.2.1",
|
||||||
|
"jszip": "^3.10.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"marked": "^4.3.0",
|
"marked": "^4.3.0",
|
||||||
"shortid": "^2.2.16",
|
"shortid": "^2.2.16",
|
||||||
@@ -52,6 +54,7 @@
|
|||||||
"@tsconfig/node18": "^2.0.1",
|
"@tsconfig/node18": "^2.0.1",
|
||||||
"@types/crypto-js": "^4.1.1",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/dompurify": "^3.0.2",
|
"@types/dompurify": "^3.0.2",
|
||||||
|
"@types/file-saver": "^2.0.5",
|
||||||
"@types/lodash-es": "^4.17.7",
|
"@types/lodash-es": "^4.17.7",
|
||||||
"@types/node": "^20.2.1",
|
"@types/node": "^20.2.1",
|
||||||
"@types/shortid": "^0.0.29",
|
"@types/shortid": "^0.0.29",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const emit = defineEmits<{
|
|||||||
<template #activator="{ open }">
|
<template #activator="{ open }">
|
||||||
<UIButton size="sm" @click="open"><i class="fas fa-fw fa-trash" /></UIButton>
|
<UIButton size="sm" @click="open"><i class="fas fa-fw fa-trash" /></UIButton>
|
||||||
</template>
|
</template>
|
||||||
<template #title>Delete note</template>
|
<template #title><i class="fas fa-fw fa-trash mr-2" />Delete note</template>
|
||||||
<template #default>Are you sure you want to delete this note?</template>
|
<template #default>Are you sure you want to delete this note?</template>
|
||||||
<template #actions="{ close }">
|
<template #actions="{ close }">
|
||||||
<UIButton size="sm" color="primary" @click="emit('delete', close)">Delete notes</UIButton>
|
<UIButton size="sm" color="primary" @click="emit('delete', close)">Delete notes</UIButton>
|
||||||
@@ -28,7 +28,7 @@ const emit = defineEmits<{
|
|||||||
<template #activator="{ open }">
|
<template #activator="{ open }">
|
||||||
<UIButton size="sm" @click="open"><i class="fas fa-fw fa-sitemap" /></UIButton>
|
<UIButton size="sm" @click="open"><i class="fas fa-fw fa-sitemap" /></UIButton>
|
||||||
</template>
|
</template>
|
||||||
<template #title>Set root note</template>
|
<template #title><i class="fas fa-fw fa-sitemap mr-2" />Set root note</template>
|
||||||
<template #default>Are you sure you want to set this note as root note?</template>
|
<template #default>Are you sure you want to set this note as root note?</template>
|
||||||
<template #actions="{ close }">
|
<template #actions="{ close }">
|
||||||
<UIButton size="sm" @click="close">Cancel</UIButton>
|
<UIButton size="sm" @click="close">Cancel</UIButton>
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { user } from '@/composables/useFirebase'
|
import { user } from '@/composables/useFirebase'
|
||||||
|
import { encryptionKey, enableEncryption, disableEncryption } from '@/composables/useEncryption'
|
||||||
|
import { notes } from '@/composables/useNotes'
|
||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
|
import JSZip from 'jszip'
|
||||||
|
import FileSaver from 'file-saver'
|
||||||
|
|
||||||
const verificationEmailSent = ref(false)
|
const verificationEmailSent = ref(false)
|
||||||
const sendVerificationMail = () => {
|
const sendVerificationMail = () => {
|
||||||
@@ -8,18 +12,49 @@ const sendVerificationMail = () => {
|
|||||||
user.value.sendEmailVerification()
|
user.value.sendEmailVerification()
|
||||||
verificationEmailSent.value = true
|
verificationEmailSent.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exportNotes = async () => {
|
||||||
|
const zip = new JSZip()
|
||||||
|
notes.value.forEach((note) => {
|
||||||
|
zip.file(`${note.title}-${note.id}.md`, note.content)
|
||||||
|
})
|
||||||
|
const blob = await zip.generateAsync({ type: 'blob' })
|
||||||
|
const currentDate = format(new Date(), 'yyyyMMdd')
|
||||||
|
FileSaver.saveAs(blob, `contexted-${user.value?.email}-${currentDate}.zip`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const showEncryptionDialog = ref(false)
|
||||||
|
watch(showEncryptionDialog, () => {
|
||||||
|
passphrase.value = ''
|
||||||
|
})
|
||||||
|
const passphrase = ref('')
|
||||||
|
const toggleEncryptionError = ref('')
|
||||||
|
|
||||||
|
const encryptionEnabled = computed(() => Boolean(encryptionKey.value))
|
||||||
|
|
||||||
|
const toggleEncryption = async () => {
|
||||||
|
const result = encryptionEnabled.value
|
||||||
|
? await disableEncryption(passphrase.value)
|
||||||
|
: await enableEncryption(passphrase.value)
|
||||||
|
if (typeof result === 'string') {
|
||||||
|
toggleEncryptionError.value = result
|
||||||
|
} else {
|
||||||
|
toggleEncryptionError.value = ''
|
||||||
|
showEncryptionDialog.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<UIModal size="lg">
|
<UIModal size="lg">
|
||||||
<template #activator="{ open }">
|
<template #activator="{ open }">
|
||||||
<UIDropdownItem @click="open">
|
<UIDropdownItem @click="open">
|
||||||
<i class="fa-fw fa-solid fa-sliders" />
|
<i class="fa-fw fa-solid fa-sliders" />
|
||||||
Settings
|
Account settings
|
||||||
</UIDropdownItem>
|
</UIDropdownItem>
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
<i class="fa-fw fa-solid fa-sliders mr-2" />
|
<i class="fa-fw fa-solid fa-sliders mr-2" />
|
||||||
Settings
|
Account settings
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
@@ -62,17 +97,75 @@ const sendVerificationMail = () => {
|
|||||||
<UICard>
|
<UICard>
|
||||||
<template #title>Notes</template>
|
<template #title>Notes</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="w-full flex-row sm:flex items-center">
|
<div class="items-top w-full flex-row sm:flex">
|
||||||
<div class="font-bold sm:w-4/12">Export notes</div>
|
<div class="font-bold sm:w-4/12">Export notes</div>
|
||||||
<UIButton size="sm" color="secondary"><i class="fa-fw fa-solid fa-file-export mr-2"></i>Export notes</UIButton>
|
<UIButton size="sm" @click="exportNotes">
|
||||||
|
<i class="fa-fw fa-solid fa-file-export mr-2"></i>
|
||||||
|
Export notes
|
||||||
|
</UIButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex-row sm:flex items-center">
|
<div class="items-top w-full flex-row sm:flex">
|
||||||
<div class="font-bold sm:w-4/12">Delete account</div>
|
<div class="font-bold sm:w-4/12">Delete account</div>
|
||||||
<UIButton size="sm" color="error"><i class="fa-fw fa-solid fa-trash mr-2"></i>Delete account</UIButton>
|
<UIButton size="sm" color="error">
|
||||||
|
<i class="fa-fw fa-solid fa-trash mr-2"></i>
|
||||||
|
Delete account
|
||||||
|
</UIButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex-row sm:flex items-center">
|
<div class="items-top w-full flex-row sm:flex">
|
||||||
<div class="font-bold sm:w-4/12">End-to-end encryption</div>
|
<div class="font-bold sm:w-4/12">End-to-end encryption</div>
|
||||||
<UIButton size="sm" color="secondary"><i class="fa-fw fa-solid fa-key mr-2"></i>Enable end-to-end encryption</UIButton>
|
<div>
|
||||||
|
<template v-if="!encryptionEnabled">
|
||||||
|
<UIButton
|
||||||
|
size="sm"
|
||||||
|
@click="showEncryptionDialog = true"
|
||||||
|
v-if="showEncryptionDialog === false"
|
||||||
|
>
|
||||||
|
<i class="fa-fw fa-solid fa-key mr-2"></i>
|
||||||
|
Enable end-to-end encryption
|
||||||
|
</UIButton>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<UIButton
|
||||||
|
size="sm"
|
||||||
|
@click="showEncryptionDialog = true"
|
||||||
|
v-if="showEncryptionDialog === false"
|
||||||
|
>
|
||||||
|
<i class="fa-fw fa-solid fa-key mr-2"></i>
|
||||||
|
Disable end-to-end encryption
|
||||||
|
</UIButton>
|
||||||
|
</template>
|
||||||
|
<UIAlert color="info" density="compact" v-if="showEncryptionDialog">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div>
|
||||||
|
Enter your passphrase to
|
||||||
|
{{ encryptionEnabled ? 'disable' : 'enable' }}
|
||||||
|
encryption
|
||||||
|
</div>
|
||||||
|
<UIInputText
|
||||||
|
size="sm"
|
||||||
|
type="password"
|
||||||
|
:color="toggleEncryptionError ? 'error' : 'regular'"
|
||||||
|
v-model="passphrase"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
<UIAlert density="compact" color="error" v-if="toggleEncryptionError">
|
||||||
|
<i class="fa-solid fa-triangle-exclamation"></i>
|
||||||
|
{{ toggleEncryptionError }}
|
||||||
|
</UIAlert>
|
||||||
|
<div class="flex justify-end space-x-2">
|
||||||
|
<UIButton size="sm" @click="showEncryptionDialog = false">Close</UIButton>
|
||||||
|
<UIButton
|
||||||
|
:disabled="passphrase.length === 0"
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
@click="toggleEncryption"
|
||||||
|
>
|
||||||
|
{{ encryptionEnabled ? 'Disable' : 'Enable' }} encryption
|
||||||
|
</UIButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UIAlert>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UICard>
|
</UICard>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Props {
|
interface Props {
|
||||||
color?: 'info' | 'success' | 'warning' | 'error'
|
color?: 'info' | 'success' | 'warning' | 'error'
|
||||||
|
density?: 'regular' | 'compact'
|
||||||
}
|
}
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
color: 'info'
|
color: 'info',
|
||||||
|
density: 'regular'
|
||||||
})
|
})
|
||||||
|
|
||||||
const styleClass = computed(() => {
|
const styleClass = computed(() => {
|
||||||
@@ -13,12 +15,17 @@ const styleClass = computed(() => {
|
|||||||
'warning': 'dui-alert-warning',
|
'warning': 'dui-alert-warning',
|
||||||
'error': 'dui-alert-error'
|
'error': 'dui-alert-error'
|
||||||
}
|
}
|
||||||
|
const densityVariants = {
|
||||||
|
'regular': 'py-4 px-4',
|
||||||
|
'compact': 'py-2 px-4'
|
||||||
|
}
|
||||||
const colorClass = colorVariants[props.color]
|
const colorClass = colorVariants[props.color]
|
||||||
return [colorClass]
|
const densityClass = densityVariants[props.density]
|
||||||
|
return [colorClass, densityClass]
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="dui-alert shadow-lg items-start" :class="styleClass">
|
<div class="dui-alert shadow-lg items-start" :class="styleClass">
|
||||||
<div class="flex items-center"><slot></slot></div>
|
<div class="flex items-center w-full"><slot></slot></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const props = withDefaults(
|
|||||||
open?: boolean
|
open?: boolean
|
||||||
persistent?: boolean
|
persistent?: boolean
|
||||||
size?: 'sm' | 'md' | 'lg'
|
size?: 'sm' | 'md' | 'lg'
|
||||||
|
icon?: string
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
open: false,
|
open: false,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { doc, getDoc } from 'firebase/firestore'
|
import { doc, getDoc, setDoc } from 'firebase/firestore'
|
||||||
import { user, db } from '@/composables/useFirebase'
|
import { user, db } from '@/composables/useFirebase'
|
||||||
import { decrypt, encrypt, calculateClientKey } from '@/utils/crypto'
|
import { decrypt, encrypt, calculateClientKey, generateEncryptionKey } from '@/utils/crypto'
|
||||||
|
import { preferredNotesSource } from '@/composables/useSettings'
|
||||||
|
import { activeNotesSource, syncNotesToFirebase, baseNotes } from '@/composables/useNotes'
|
||||||
|
|
||||||
function getClientKeysFromLocalStorage(): { [uid: string]: string } {
|
function getClientKeysFromLocalStorage(): { [uid: string]: string } {
|
||||||
try {
|
try {
|
||||||
@@ -42,20 +44,38 @@ export const verifyClientKey = (clientKey: ClientKey) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedEncryptionKey = ref<EncryptedEncryptionKey>()
|
const removeClientKey = () => {
|
||||||
|
if (!user.value) return
|
||||||
|
const clientKeys = structuredClone(getClientKeysFromLocalStorage())
|
||||||
|
delete clientKeys[user.value?.uid]
|
||||||
|
localStorage.setItem('clientKeys', JSON.stringify(clientKeys))
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedEncryptionKey = ref<EncryptedEncryptionKey | null>()
|
||||||
|
|
||||||
async function getEncryptedEncryptionKey(): Promise<EncryptedEncryptionKey | void> {
|
async function getEncryptedEncryptionKey(): Promise<EncryptedEncryptionKey | void> {
|
||||||
if (!user.value || !db.value) return
|
if (!user.value || !db.value) return
|
||||||
const data = (await getDoc(doc(db.value, 'encryptionKeys', user.value?.uid || ''))).data()
|
const data = (await getDoc(doc(db.value, 'encryptionKeys', user.value.uid))).data()
|
||||||
return data?.key
|
return data?.key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setEncryptedEncryptionKey(
|
||||||
|
encryptedEncryptionKey: EncryptedEncryptionKey | null
|
||||||
|
): Promise<void> {
|
||||||
|
if (!user.value || !db.value) return
|
||||||
|
const docRef = doc(db.value, 'encryptionKeys', user.value.uid)
|
||||||
|
await setDoc(docRef, { key: encryptedEncryptionKey })
|
||||||
|
}
|
||||||
|
|
||||||
export const encryptionKey = ref<EncryptionKey | null>()
|
export const encryptionKey = ref<EncryptionKey | null>()
|
||||||
|
|
||||||
export async function getEncryptionKey() {
|
export async function getEncryptionKey() {
|
||||||
encryptedEncryptionKey.value = (await getEncryptedEncryptionKey()) || undefined
|
encryptedEncryptionKey.value = (await getEncryptedEncryptionKey()) || undefined
|
||||||
if (!encryptedEncryptionKey.value || !clientKey.value) return
|
if (!encryptedEncryptionKey.value || !clientKey.value) {
|
||||||
encryptionKey.value = decrypt(encryptedEncryptionKey.value, clientKey.value)
|
encryptionKey.value = null
|
||||||
|
} else {
|
||||||
|
encryptionKey.value = decrypt(encryptedEncryptionKey.value, clientKey.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const passphraseRequired = computed(() => {
|
export const passphraseRequired = computed(() => {
|
||||||
@@ -63,10 +83,15 @@ export const passphraseRequired = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const decryptNote = (note: BaseNote, key: EncryptionKey) => {
|
const decryptNote = (note: BaseNote, key: EncryptionKey) => {
|
||||||
return {
|
try {
|
||||||
...note,
|
return {
|
||||||
title: decrypt(note.title, key),
|
...note,
|
||||||
content: decrypt(note.content, key)
|
title: decrypt(note.title, key),
|
||||||
|
content: decrypt(note.content, key)
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error)
|
||||||
|
return note
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,3 +116,34 @@ export const encryptNotes = (notes: BaseNotes, encryptionKey: EncryptionKey) =>
|
|||||||
)
|
)
|
||||||
return encryptedNotes
|
return encryptedNotes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const verifyPassphrase = (passphrase: string) => {
|
||||||
|
const calculatedClientKey = calculateClientKey(passphrase)
|
||||||
|
return calculatedClientKey === clientKey.value
|
||||||
|
}
|
||||||
|
|
||||||
|
export const disableEncryption = async (passphrase: string) => {
|
||||||
|
if (!encryptionKey.value) return "Encryption key doesn't exist."
|
||||||
|
if (!verifyPassphrase(passphrase)) return 'Passphrase is incorrect.'
|
||||||
|
preferredNotesSource.value = 'firebase'
|
||||||
|
if (activeNotesSource.value !== 'firebase') throw Error('Something went wrong.')
|
||||||
|
await setEncryptedEncryptionKey(null)
|
||||||
|
encryptedEncryptionKey.value = null
|
||||||
|
encryptionKey.value = undefined
|
||||||
|
removeClientKey()
|
||||||
|
await syncNotesToFirebase(baseNotes.value)
|
||||||
|
getEncryptionKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enableEncryption = async (passphrase: string) => {
|
||||||
|
preferredNotesSource.value = 'firebase'
|
||||||
|
if (activeNotesSource.value !== 'firebase') throw Error('Something went wrong.')
|
||||||
|
const candidateEncryptionKey = generateEncryptionKey()
|
||||||
|
const candidateClientKey = calculateClientKey(passphrase)
|
||||||
|
const candidateEncryptedEncryptionKey = encrypt(candidateEncryptionKey, candidateClientKey)
|
||||||
|
await setEncryptedEncryptionKey(candidateEncryptedEncryptionKey)
|
||||||
|
encryptedEncryptionKey.value = candidateEncryptedEncryptionKey
|
||||||
|
encryptionKey.value = candidateEncryptionKey
|
||||||
|
setClientKey(passphrase)
|
||||||
|
syncNotesToFirebase(baseNotes.value)
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,36 +39,42 @@ watchEffect(() => {
|
|||||||
activeNotesSource.value = getSource()
|
activeNotesSource.value = getSource()
|
||||||
})
|
})
|
||||||
|
|
||||||
const baseNotes = ref<BaseNotes>({})
|
export const baseNotes = ref<BaseNotes>({})
|
||||||
|
|
||||||
|
const syncNotesLocal = (notes: BaseNotes) => {
|
||||||
|
localStorage.setItem('notes', JSON.stringify(notes))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const syncNotesToFirebase = async (newNotes: BaseNotes, oldNotes?: BaseNotes) => {
|
||||||
|
if (!db.value) throw Error("Database undefined, can't sync to Firebase")
|
||||||
|
if (!user.value) throw Error("User undefined, can't sync to Firebase")
|
||||||
|
const notes = encryptionKey.value
|
||||||
|
? encryptNotes(baseNotes.value, encryptionKey.value)
|
||||||
|
: baseNotes.value
|
||||||
|
try {
|
||||||
|
const docRef = doc(db.value, 'pages', user.value.uid)
|
||||||
|
if (oldNotes) {
|
||||||
|
const notesToDelete = Object.keys(oldNotes).filter((x) => !Object.keys(newNotes).includes(x))
|
||||||
|
await Promise.all(
|
||||||
|
notesToDelete.map((noteId: string) => {
|
||||||
|
return updateDoc(docRef, { [noteId]: deleteField() })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
await updateDoc(docRef, notes)
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
baseNotes,
|
baseNotes,
|
||||||
async (newBaseNotes, oldBaseNotes) => {
|
async (newBaseNotes, oldBaseNotes) => {
|
||||||
if (!activeNotesSource.value || Object.keys(baseNotes.value).length === 0) return
|
if (!activeNotesSource.value || Object.keys(baseNotes.value).length === 0) return
|
||||||
console.log()
|
|
||||||
|
|
||||||
if (activeNotesSource.value === 'local') {
|
if (activeNotesSource.value === 'local') {
|
||||||
localStorage.setItem('notes', JSON.stringify(baseNotes.value))
|
syncNotesLocal(baseNotes.value)
|
||||||
} else if (activeNotesSource.value === 'firebase') {
|
} else if (activeNotesSource.value === 'firebase') {
|
||||||
if (!db.value) throw Error("Database undefined, can't sync to Firebase")
|
syncNotesToFirebase(newBaseNotes, oldBaseNotes)
|
||||||
if (!user.value) throw Error("User undefined, can't sync to Firebase")
|
|
||||||
const notes = encryptionKey.value
|
|
||||||
? encryptNotes(baseNotes.value, encryptionKey.value)
|
|
||||||
: baseNotes.value
|
|
||||||
|
|
||||||
const notesToDelete = Object.keys(oldBaseNotes).filter(
|
|
||||||
(x) => !Object.keys(newBaseNotes).includes(x)
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
const docRef = doc(db.value, 'pages', user.value.uid)
|
|
||||||
await Promise.all(
|
|
||||||
notesToDelete.map((noteId: string) => {
|
|
||||||
return updateDoc(docRef, { [noteId]: deleteField() })
|
|
||||||
})
|
|
||||||
)
|
|
||||||
await updateDoc(docRef, notes)
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
|
|||||||
@@ -17,3 +17,7 @@ export const decrypt = (encryptedMessage: string, key: string): string => {
|
|||||||
export const encrypt = (unencryptedMessage: string, key: string): string => {
|
export const encrypt = (unencryptedMessage: string, key: string): string => {
|
||||||
return CryptoJS.AES.encrypt(encryptionPrefix + unencryptedMessage, key).toString()
|
return CryptoJS.AES.encrypt(encryptionPrefix + unencryptedMessage, key).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const generateEncryptionKey = () => {
|
||||||
|
return CryptoJS.lib.WordArray.random(16).toString(CryptoJS.enc.Hex)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user