Compare commits
756 Commits
auth-v3.0.
...
photosd-v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20a8df378c | ||
|
|
d9ec95b8ab | ||
|
|
c16b6a7d43 | ||
|
|
d3dccb1bea | ||
|
|
f115ce4a0d | ||
|
|
7c8febfc1b | ||
|
|
bffbc6041b | ||
|
|
7640789f08 | ||
|
|
95c04b554c | ||
|
|
5e15fccb75 | ||
|
|
7047383e09 | ||
|
|
f02bd096b0 | ||
|
|
617ae0701b | ||
|
|
8e136ecdc1 | ||
|
|
0ea408379a | ||
|
|
eeab98c768 | ||
|
|
e881c15026 | ||
|
|
21b6316996 | ||
|
|
349a5021a5 | ||
|
|
4aa92ffc43 | ||
|
|
3f5a8a503b | ||
|
|
9fe894e368 | ||
|
|
e537ba0a9a | ||
|
|
5033ab2fed | ||
|
|
987cc1c520 | ||
|
|
4773c7c262 | ||
|
|
936e0470e6 | ||
|
|
ecbb71a97b | ||
|
|
544a5a9ccc | ||
|
|
fdcc6b6997 | ||
|
|
73ad758191 | ||
|
|
a3dc691885 | ||
|
|
b25dbfc10b | ||
|
|
13c042f692 | ||
|
|
62e4a6c344 | ||
|
|
8dad88eca6 | ||
|
|
6ccb61b425 | ||
|
|
b402c6ae32 | ||
|
|
52251ad654 | ||
|
|
5ff9f408eb | ||
|
|
06bf2ddad4 | ||
|
|
0214ccf680 | ||
|
|
2e1fde906e | ||
|
|
df4364525d | ||
|
|
661d0383fb | ||
|
|
6f577d150a | ||
|
|
6086e139e4 | ||
|
|
5fef9b21e5 | ||
|
|
7069e15b79 | ||
|
|
44e165b8ee | ||
|
|
b0b82aabd8 | ||
|
|
d043658331 | ||
|
|
9616640fce | ||
|
|
10e55b6739 | ||
|
|
d661f4ac1f | ||
|
|
2865b33fc2 | ||
|
|
0f4459112e | ||
|
|
f9b8c5287d | ||
|
|
2ac968fdf6 | ||
|
|
440f9293d8 | ||
|
|
d1968e46e5 | ||
|
|
70b74fc285 | ||
|
|
c92a117e8d | ||
|
|
d7371392fe | ||
|
|
b5972a6395 | ||
|
|
ebfd8909a9 | ||
|
|
83d6d99469 | ||
|
|
1322e5df79 | ||
|
|
3b951f237f | ||
|
|
162107b3a9 | ||
|
|
54936303c8 | ||
|
|
8830a60ecf | ||
|
|
071a63a81c | ||
|
|
aa6e5c9234 | ||
|
|
5c916374f3 | ||
|
|
c5cd6cbbca | ||
|
|
cfad9f841e | ||
|
|
6d09d1f9b7 | ||
|
|
e1ce2e5e84 | ||
|
|
6f40cbe27e | ||
|
|
8e10c8bec6 | ||
|
|
eb271088a4 | ||
|
|
fde6e14440 | ||
|
|
cd433aa39e | ||
|
|
2510226a57 | ||
|
|
ecd4201304 | ||
|
|
4d11623f77 | ||
|
|
4519dc94b8 | ||
|
|
57ff75b855 | ||
|
|
d4be782b9c | ||
|
|
24858ab73b | ||
|
|
99545f0038 | ||
|
|
072ee3861b | ||
|
|
881993ed65 | ||
|
|
83516a7f27 | ||
|
|
8117a2929c | ||
|
|
8821372515 | ||
|
|
825a215213 | ||
|
|
be61cd08b8 | ||
|
|
bab30ec508 | ||
|
|
064af381c5 | ||
|
|
840b415254 | ||
|
|
711c858d06 | ||
|
|
4f60cabdd0 | ||
|
|
8fbcef4221 | ||
|
|
49bfe5aabb | ||
|
|
11584ce089 | ||
|
|
b8b2d58734 | ||
|
|
920685e15c | ||
|
|
56fe538f07 | ||
|
|
942231c521 | ||
|
|
c5b10b14d1 | ||
|
|
df80d9c355 | ||
|
|
e90ab70cc8 | ||
|
|
53dc3bace9 | ||
|
|
82ec83caf3 | ||
|
|
2f5c966892 | ||
|
|
45b1f82032 | ||
|
|
cb148ea3b1 | ||
|
|
ed660c36df | ||
|
|
2920e04aa5 | ||
|
|
ca44202fcd | ||
|
|
023610cebd | ||
|
|
d11e94c939 | ||
|
|
cfb1b8423b | ||
|
|
4d84e966b0 | ||
|
|
3bef2e8268 | ||
|
|
f2bcf1744f | ||
|
|
8d4629254c | ||
|
|
a0980a9638 | ||
|
|
4fada9bdf9 | ||
|
|
2bc95782a6 | ||
|
|
b36c4398c1 | ||
|
|
e183e1f9dd | ||
|
|
a8c267e2b0 | ||
|
|
8d8b113ef8 | ||
|
|
6f389cb64d | ||
|
|
f534984c0e | ||
|
|
a7e5de7493 | ||
|
|
49ca581904 | ||
|
|
e82e243b77 | ||
|
|
26f421c77e | ||
|
|
d4f0384f13 | ||
|
|
2a07684de0 | ||
|
|
e4f86794be | ||
|
|
b5a3821933 | ||
|
|
c7defa31f5 | ||
|
|
374b803ecc | ||
|
|
0769ba2fff | ||
|
|
95dc3d1e6c | ||
|
|
da5270daa7 | ||
|
|
a3de155a10 | ||
|
|
a761c06396 | ||
|
|
369680b4a8 | ||
|
|
24ea02c521 | ||
|
|
1fb95f7d7d | ||
|
|
c82ef796f2 | ||
|
|
f1c76adb38 | ||
|
|
46db1c240c | ||
|
|
8b5ad13595 | ||
|
|
6511179766 | ||
|
|
bbacbb08b6 | ||
|
|
67ca028dbf | ||
|
|
2f2d988eaa | ||
|
|
d0f585fc97 | ||
|
|
c86be54ac1 | ||
|
|
d24c116d14 | ||
|
|
a279c442b8 | ||
|
|
5b76225542 | ||
|
|
e2f2921d78 | ||
|
|
86584e7424 | ||
|
|
05a400102a | ||
|
|
9c7c0b9592 | ||
|
|
e807712cdc | ||
|
|
e468ecc98c | ||
|
|
dc80aac487 | ||
|
|
1a06fce8f2 | ||
|
|
933212ba59 | ||
|
|
26d8ecda08 | ||
|
|
8fc897ad16 | ||
|
|
53a8de9ac4 | ||
|
|
a99a179ef9 | ||
|
|
cdba99a7c2 | ||
|
|
b03b9fd314 | ||
|
|
4019afdd90 | ||
|
|
c12130d357 | ||
|
|
4427352f51 | ||
|
|
ac06f67891 | ||
|
|
27dab94782 | ||
|
|
99616b46a1 | ||
|
|
d72a561a9b | ||
|
|
75baee00c2 | ||
|
|
8b696b1242 | ||
|
|
aebe12bd9e | ||
|
|
fcb86da03c | ||
|
|
99af0ff294 | ||
|
|
7cef60f8b9 | ||
|
|
31b6572e17 | ||
|
|
d07a46f514 | ||
|
|
547d03049a | ||
|
|
18ab41b9ec | ||
|
|
e9938c2ac4 | ||
|
|
089ed89045 | ||
|
|
9c11a7f4b7 | ||
|
|
543fb835f3 | ||
|
|
0b3ca8db69 | ||
|
|
05e7863bdc | ||
|
|
a2ee8a2ee9 | ||
|
|
969154baff | ||
|
|
27525907af | ||
|
|
92e89d3589 | ||
|
|
9898a7c221 | ||
|
|
ef788b16b9 | ||
|
|
5f7577309a | ||
|
|
cd39e5e9cd | ||
|
|
588662d1ce | ||
|
|
4f98e72a58 | ||
|
|
5bd3f6076b | ||
|
|
adcdba3f8f | ||
|
|
5c4c6f2677 | ||
|
|
f217d85b70 | ||
|
|
52448cd2a2 | ||
|
|
dca76f304c | ||
|
|
26f6ab0464 | ||
|
|
90c01a19a5 | ||
|
|
38e23ca1b5 | ||
|
|
5698ee12a3 | ||
|
|
c3bbceae49 | ||
|
|
95ef21ae4f | ||
|
|
0ce729a312 | ||
|
|
73b78916de | ||
|
|
864e4c6dd1 | ||
|
|
00de818e65 | ||
|
|
41fe7ad794 | ||
|
|
13843bf52d | ||
|
|
6d630e0c2a | ||
|
|
7bd10ed78b | ||
|
|
ce0442a5dd | ||
|
|
b950fde3f2 | ||
|
|
1ab844da36 | ||
|
|
eb7611a6d1 | ||
|
|
ce045fb680 | ||
|
|
594d0e7ea0 | ||
|
|
8c79aedd19 | ||
|
|
401ae85f40 | ||
|
|
3065b392f3 | ||
|
|
2a587039b0 | ||
|
|
6af39d52e3 | ||
|
|
e15dbc2023 | ||
|
|
ed2c63cf03 | ||
|
|
b04538ada2 | ||
|
|
52cd2d30a1 | ||
|
|
0d0d501518 | ||
|
|
5b7dcddab3 | ||
|
|
809b02cb26 | ||
|
|
cb94d95d94 | ||
|
|
4665cac03d | ||
|
|
98d1a1c219 | ||
|
|
3b4897b86a | ||
|
|
1042332f5b | ||
|
|
c71850be07 | ||
|
|
c0a6918c09 | ||
|
|
c66a74d1c7 | ||
|
|
80881816f3 | ||
|
|
39a3a48fd3 | ||
|
|
5dbe46092a | ||
|
|
6e6da8152d | ||
|
|
f570773f23 | ||
|
|
b43e6e5981 | ||
|
|
2dc7d19784 | ||
|
|
c789684c31 | ||
|
|
d539eb9b1b | ||
|
|
c8f3df3969 | ||
|
|
5f771e923c | ||
|
|
8acb2a1b98 | ||
|
|
0fa0bf124a | ||
|
|
1b6d362314 | ||
|
|
1987f2354a | ||
|
|
2ab2a13dc0 | ||
|
|
70e198ee7f | ||
|
|
b3e7bab0cb | ||
|
|
23acf45d6b | ||
|
|
4ad8d0c0fd | ||
|
|
da06653c6a | ||
|
|
ea47936231 | ||
|
|
fc46552b0f | ||
|
|
532a9f64ff | ||
|
|
910013572d | ||
|
|
c61263f179 | ||
|
|
206a8a538a | ||
|
|
9e69798d79 | ||
|
|
5948714aff | ||
|
|
08a23d8733 | ||
|
|
0814fd42d1 | ||
|
|
dbe3e9a7d8 | ||
|
|
94f5822e72 | ||
|
|
851cd77c50 | ||
|
|
2709298df0 | ||
|
|
eee9a32b9a | ||
|
|
4a84309e23 | ||
|
|
6aeaea65ca | ||
|
|
61eb8d4282 | ||
|
|
a3b19162f4 | ||
|
|
c8d0ccfe6a | ||
|
|
bb31f44227 | ||
|
|
6ab5015b9d | ||
|
|
d77b9d06f9 | ||
|
|
9758b85e96 | ||
|
|
e8445d99fb | ||
|
|
177a04830b | ||
|
|
3861e48737 | ||
|
|
f60ff6d8df | ||
|
|
365e8e6eb8 | ||
|
|
f757c996e7 | ||
|
|
71e7e660b2 | ||
|
|
ff94ceb254 | ||
|
|
54b0374680 | ||
|
|
33ab6809e2 | ||
|
|
c9a2494ac8 | ||
|
|
03ded09cb4 | ||
|
|
e28a6b5290 | ||
|
|
f6e4d4c7c9 | ||
|
|
8031f27feb | ||
|
|
ec04becd0e | ||
|
|
1a4b3199f1 | ||
|
|
f7137b721e | ||
|
|
080d5630a8 | ||
|
|
af61774d93 | ||
|
|
0e1b490371 | ||
|
|
6bb126e58f | ||
|
|
369ff7833c | ||
|
|
658a258ddc | ||
|
|
9c377d9ced | ||
|
|
c27f4a64df | ||
|
|
4d9b7d7632 | ||
|
|
1f00330fd4 | ||
|
|
6c178a4476 | ||
|
|
f3bd395f11 | ||
|
|
9d30ffc96f | ||
|
|
8fe0a31da3 | ||
|
|
06fae3836e | ||
|
|
6ee237716e | ||
|
|
d86ce619c0 | ||
|
|
93b264443c | ||
|
|
47e8474466 | ||
|
|
dd80b2174f | ||
|
|
fa28d6d6db | ||
|
|
f8e5bd3d66 | ||
|
|
ff2d838b64 | ||
|
|
9fd94c63d9 | ||
|
|
8abcd39966 | ||
|
|
a65e0ddfa4 | ||
|
|
406e7bd5bd | ||
|
|
a7f0dc74fd | ||
|
|
b49d1323db | ||
|
|
16b79bcf4a | ||
|
|
16e197455b | ||
|
|
cd27168f5f | ||
|
|
1c7f25723e | ||
|
|
025fe35999 | ||
|
|
892a90d83b | ||
|
|
94f179ebab | ||
|
|
f2ea1a05c1 | ||
|
|
b88d6d26a6 | ||
|
|
18194dc61a | ||
|
|
f7324d5388 | ||
|
|
93488e149d | ||
|
|
23b0ea67ae | ||
|
|
a2599f3415 | ||
|
|
2cce5fb17c | ||
|
|
9205907588 | ||
|
|
a282c6cb40 | ||
|
|
cec60520d9 | ||
|
|
5c0f183740 | ||
|
|
03150482f7 | ||
|
|
5fcb1de540 | ||
|
|
157f3696e4 | ||
|
|
a60c50fe97 | ||
|
|
6544ed3d3d | ||
|
|
b4d0eb843b | ||
|
|
c40a051f5f | ||
|
|
0b76287f80 | ||
|
|
df85e70a37 | ||
|
|
9734797bac | ||
|
|
b430aeb7c4 | ||
|
|
ff0f940798 | ||
|
|
5988052521 | ||
|
|
c929d3dc74 | ||
|
|
bf2873821d | ||
|
|
eaecf91aa1 | ||
|
|
49f96dbea1 | ||
|
|
b9972e131a | ||
|
|
c318a15236 | ||
|
|
1a545aeef6 | ||
|
|
d40d119b82 | ||
|
|
e71410af4e | ||
|
|
612e81d74e | ||
|
|
bf1f4b26cf | ||
|
|
de7b80a352 | ||
|
|
cf3728eee8 | ||
|
|
5b9c173b0e | ||
|
|
4179d183bd | ||
|
|
fbae7b6fd0 | ||
|
|
62c9b2afc2 | ||
|
|
cd81bbe19e | ||
|
|
39a6b3cd6b | ||
|
|
d14a6591d2 | ||
|
|
6b6edfb5bf | ||
|
|
7b20bbd5a2 | ||
|
|
61a62f5656 | ||
|
|
0376af8d38 | ||
|
|
85aaf94c89 | ||
|
|
af53585f6c | ||
|
|
22fbf0a1be | ||
|
|
4acd17f06b | ||
|
|
05e7a998e2 | ||
|
|
bbc44d6ac1 | ||
|
|
b1da1dfe05 | ||
|
|
26c1dda600 | ||
|
|
2f0112d5de | ||
|
|
ca0fa88bb5 | ||
|
|
45093fcc0c | ||
|
|
776915e659 | ||
|
|
4a14017cff | ||
|
|
67e054a26d | ||
|
|
6f073b007b | ||
|
|
284799bc7a | ||
|
|
54c54d50c6 | ||
|
|
f11960981a | ||
|
|
9973e5c701 | ||
|
|
8fbc7b3937 | ||
|
|
d09a7b290b | ||
|
|
bd627a6e54 | ||
|
|
3ddd5bff2d | ||
|
|
f7b7bae0af | ||
|
|
62c3ca3ecc | ||
|
|
a967d2fbd0 | ||
|
|
3c86a9bc06 | ||
|
|
450981a5fb | ||
|
|
ad2dabcc96 | ||
|
|
8b16b4632f | ||
|
|
bb37630bae | ||
|
|
66cb95e32c | ||
|
|
ea51cdfc77 | ||
|
|
4d41f2d64c | ||
|
|
266796f619 | ||
|
|
57a587301b | ||
|
|
90c15774d7 | ||
|
|
7d46de139e | ||
|
|
dd3243492a | ||
|
|
ea7619d405 | ||
|
|
7d8ade7fe4 | ||
|
|
ddf18bd036 | ||
|
|
84a03dafe3 | ||
|
|
dc5b0b4393 | ||
|
|
36d8c2a427 | ||
|
|
b63a15a521 | ||
|
|
53452344f3 | ||
|
|
a119d544af | ||
|
|
67d9e650ba | ||
|
|
61d35159fa | ||
|
|
593ece7681 | ||
|
|
45a103f66a | ||
|
|
27c6474f06 | ||
|
|
660f6c645b | ||
|
|
90cffef7be | ||
|
|
d6f30546b9 | ||
|
|
a9e0aa13ff | ||
|
|
1496b60895 | ||
|
|
2f7923b097 | ||
|
|
d5d7efd657 | ||
|
|
c4b93019d5 | ||
|
|
0943d1db8c | ||
|
|
822e82d709 | ||
|
|
51eec12af5 | ||
|
|
5da4028ebf | ||
|
|
26626797ff | ||
|
|
ee3ddad4d1 | ||
|
|
730ca2119c | ||
|
|
58127591d0 | ||
|
|
c9eaa2df12 | ||
|
|
66549445d1 | ||
|
|
f167839ddc | ||
|
|
6f0a36acde | ||
|
|
1463d4199e | ||
|
|
094d4053fb | ||
|
|
0a4abada00 | ||
|
|
6bf00c40a0 | ||
|
|
959d5c78b2 | ||
|
|
2ea9b4ba84 | ||
|
|
9df98f8ffb | ||
|
|
a58fa405f7 | ||
|
|
120fb38d3f | ||
|
|
471db8e8c1 | ||
|
|
8613f5e73f | ||
|
|
22fc61633b | ||
|
|
22e7bcb3b0 | ||
|
|
3aeaf365ca | ||
|
|
5140d6c938 | ||
|
|
c7d5dde9f7 | ||
|
|
b84470f574 | ||
|
|
29a496c039 | ||
|
|
9f9038ff97 | ||
|
|
d33ba285a6 | ||
|
|
640fd48e70 | ||
|
|
52d7914ad0 | ||
|
|
554a90eec5 | ||
|
|
3555adae09 | ||
|
|
ab63ed53df | ||
|
|
c4c53cd59f | ||
|
|
e86b095480 | ||
|
|
55b2934c62 | ||
|
|
3f96209dbb | ||
|
|
9241c2e595 | ||
|
|
94f4dcb9be | ||
|
|
f543b402f8 | ||
|
|
1b77c899da | ||
|
|
1aef9cf179 | ||
|
|
f0b3c4a30a | ||
|
|
0def478b0d | ||
|
|
f11cc82e44 | ||
|
|
a3d7c53395 | ||
|
|
b4e0eb8491 | ||
|
|
bdbed2aa17 | ||
|
|
2652f39c21 | ||
|
|
6f95272400 | ||
|
|
92b4d52a40 | ||
|
|
083b7b3d95 | ||
|
|
20c33fd00b | ||
|
|
1d5366c6b6 | ||
|
|
e2e36e285f | ||
|
|
c5bcc1992c | ||
|
|
2c9b0e77ba | ||
|
|
ca7096b87c | ||
|
|
3a8b2cf7b8 | ||
|
|
69bfaf2033 | ||
|
|
0d12f17576 | ||
|
|
80d5d7e44e | ||
|
|
bfa4806d47 | ||
|
|
2c3bd39ab6 | ||
|
|
1d0cbc527a | ||
|
|
4c8e6853be | ||
|
|
4839aaaf6d | ||
|
|
7cac870a68 | ||
|
|
a5a7c4fcb2 | ||
|
|
3d91e1c481 | ||
|
|
3193139118 | ||
|
|
c354c80b1f | ||
|
|
59b132edf8 | ||
|
|
b67af0145a | ||
|
|
a3bb8fa911 | ||
|
|
2d3e3c91d2 | ||
|
|
baec693c72 | ||
|
|
362179ba8d | ||
|
|
f55c33a4d6 | ||
|
|
083eb2fc7a | ||
|
|
df50a3b759 | ||
|
|
4e7045fe71 | ||
|
|
9be81955af | ||
|
|
477f093437 | ||
|
|
b2d29ccbf8 | ||
|
|
0b0701271e | ||
|
|
c318167909 | ||
|
|
89ee10ea57 | ||
|
|
a310eca1c2 | ||
|
|
1cd5536eb1 | ||
|
|
5b411ce55a | ||
|
|
012aae17ec | ||
|
|
e6b4d220a3 | ||
|
|
c988c30910 | ||
|
|
3ae1b18bf1 | ||
|
|
a093c1dd34 | ||
|
|
25a79e4146 | ||
|
|
47630408b6 | ||
|
|
9c0a66b036 | ||
|
|
d8650aa33d | ||
|
|
a6645bce8b | ||
|
|
05816a3894 | ||
|
|
e4e75b573f | ||
|
|
3f6ef61204 | ||
|
|
326f7d647e | ||
|
|
3d7e425f48 | ||
|
|
767f2479af | ||
|
|
edceebd8fb | ||
|
|
685a3ca4c7 | ||
|
|
3a4dc21470 | ||
|
|
ce3233a01f | ||
|
|
2f8abd5b7f | ||
|
|
f5d6037e31 | ||
|
|
a03c8e3a55 | ||
|
|
f64b0238c9 | ||
|
|
06e7626206 | ||
|
|
a6dae9a661 | ||
|
|
3d84937d06 | ||
|
|
2bc8cca55f | ||
|
|
24691b8652 | ||
|
|
522d1da0e9 | ||
|
|
cef1dee2a0 | ||
|
|
3220da556d | ||
|
|
ea6e098583 | ||
|
|
610a5d8dcb | ||
|
|
73a53994f3 | ||
|
|
f67dc4893f | ||
|
|
185bed19aa | ||
|
|
3094d74b6a | ||
|
|
5c3cfb7403 | ||
|
|
5d0926ebb2 | ||
|
|
a49c7834d8 | ||
|
|
2f327b1929 | ||
|
|
b7892f4257 | ||
|
|
f5bcdd0d9e | ||
|
|
6736ad73ec | ||
|
|
75dcf18d75 | ||
|
|
e722024f8f | ||
|
|
a714c0d70b | ||
|
|
51bcf02b96 | ||
|
|
fcb79907cf | ||
|
|
35b42d4743 | ||
|
|
8fae7719b5 | ||
|
|
64aa3ac0e8 | ||
|
|
c7f3390e59 | ||
|
|
b9a71060ec | ||
|
|
d095f52051 | ||
|
|
153850742d | ||
|
|
c2cdb4e38b | ||
|
|
33ab69e2d8 | ||
|
|
b95e93778b | ||
|
|
160f279464 | ||
|
|
69bd1c8670 | ||
|
|
b21fe76b3f | ||
|
|
6ea449bd83 | ||
|
|
b99b2d1381 | ||
|
|
84f2c6d102 | ||
|
|
908e37f56f | ||
|
|
108ff34763 | ||
|
|
8ce3126c92 | ||
|
|
b1006e0843 | ||
|
|
ca0af1f53a | ||
|
|
9cb4420bbf | ||
|
|
98c444fab9 | ||
|
|
51c9094da4 | ||
|
|
815a730d59 | ||
|
|
4651c6f6d1 | ||
|
|
11666eeb33 | ||
|
|
18ec275d75 | ||
|
|
073c22ae47 | ||
|
|
6926167f3d | ||
|
|
899d1ff6a4 | ||
|
|
47128ab52d | ||
|
|
21fa0ee7a7 | ||
|
|
04f4103314 | ||
|
|
66b23d111d | ||
|
|
eccde54afe | ||
|
|
2db166bcf7 | ||
|
|
e81e088b02 | ||
|
|
9e3a3d852e | ||
|
|
f40c277aa8 | ||
|
|
ef0396983b | ||
|
|
f5873d2ade | ||
|
|
adb358ba5c | ||
|
|
ea4da2c2a4 | ||
|
|
72de042b53 | ||
|
|
57a674fd26 | ||
|
|
66f9dc98ee | ||
|
|
ff714f3420 | ||
|
|
6b4416c3a9 | ||
|
|
704e89c903 | ||
|
|
f34ecc1016 | ||
|
|
4c1462e18a | ||
|
|
bcbf03fa51 | ||
|
|
2436d2fcaa | ||
|
|
6cf942ec9e | ||
|
|
fcffd688d6 | ||
|
|
669ae855f1 | ||
|
|
3b3c802aa4 | ||
|
|
86538a6d23 | ||
|
|
815666bbe7 | ||
|
|
5a52d79a88 | ||
|
|
ec2d9a80fc | ||
|
|
65764fa982 | ||
|
|
9579e30a68 | ||
|
|
37b5b69955 | ||
|
|
ead9ed0904 | ||
|
|
b2f13c4b3d | ||
|
|
a3ce66b87f | ||
|
|
f30d1fe45f | ||
|
|
f8d1851311 | ||
|
|
206e387834 | ||
|
|
567dfb7e6b | ||
|
|
5854a9e10a | ||
|
|
94cd1991ce | ||
|
|
46644d9d4d | ||
|
|
93dec0a9f4 | ||
|
|
c79507a5d4 | ||
|
|
a170acb28b | ||
|
|
7a2f08f49a | ||
|
|
6ea003a9a1 | ||
|
|
c54c4022ad | ||
|
|
445af59829 | ||
|
|
7f573f2181 | ||
|
|
a9dc8da07c | ||
|
|
c2d2612f33 | ||
|
|
3aa3fbba6d | ||
|
|
35c8970d20 | ||
|
|
0f076e19be | ||
|
|
306430d67d | ||
|
|
716f5f1be2 | ||
|
|
a0d8dd9b9e | ||
|
|
897245d6c1 | ||
|
|
99e4d098e3 | ||
|
|
b276344f1e | ||
|
|
87e2a32d49 | ||
|
|
af11ff21f4 | ||
|
|
aab7e39ab3 | ||
|
|
7c535adff1 | ||
|
|
c8effce8fc | ||
|
|
2855181de9 | ||
|
|
25515c4403 | ||
|
|
3fe0faff6a | ||
|
|
fc7e7f4c88 | ||
|
|
39d232a937 | ||
|
|
950d6a9622 | ||
|
|
e2da01dd5b | ||
|
|
6954c960d8 | ||
|
|
0c790e64f8 | ||
|
|
1d9f4e27c7 | ||
|
|
848f3a0f6b | ||
|
|
7edfc15b67 | ||
|
|
e3e6e8e244 | ||
|
|
089d1a2389 | ||
|
|
aeb3e2be24 | ||
|
|
89e7cfb357 | ||
|
|
4e7b575c18 | ||
|
|
c6d9b7d875 | ||
|
|
b63bd89512 | ||
|
|
da59a29ea2 | ||
|
|
a135f46775 | ||
|
|
b20e8a5d17 | ||
|
|
11da0704c6 | ||
|
|
d3c7ba6874 | ||
|
|
d94fe56318 | ||
|
|
53b1dc9b67 | ||
|
|
d2b6ca53f8 | ||
|
|
d694f2796b | ||
|
|
5dd42b5a07 | ||
|
|
cd8709be9d | ||
|
|
4a9c09e896 | ||
|
|
6de7b840ae | ||
|
|
f34d2afced | ||
|
|
d41a8d7a11 | ||
|
|
ed9cb9668c | ||
|
|
f8fa6adad8 | ||
|
|
c1acc3eca1 | ||
|
|
1cd0440453 | ||
|
|
356d119fb9 | ||
|
|
5b89ef972f |
3
.github/workflows/auth-crowdin-sync.yml
vendored
@@ -2,8 +2,9 @@ name: "Sync Crowdin translations (auth)"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run Mondays at ~6:30 AM IST
|
||||
# See: [Note: Run workflow on specific days of the week]
|
||||
- cron: "50 1 * * 2"
|
||||
- cron: "50 0 * * 1"
|
||||
# Also allow manually running the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
3
.github/workflows/mobile-crowdin-sync.yml
vendored
@@ -2,8 +2,9 @@ name: "Sync Crowdin translations (mobile)"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run Mondays at ~6:30 AM IST
|
||||
# See: [Note: Run workflow on specific days of the week]
|
||||
- cron: "40 1 * * 2"
|
||||
- cron: "40 0 * * 1"
|
||||
# Also allow manually running the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
4
.github/workflows/web-crowdin-sync.yml
vendored
@@ -9,6 +9,8 @@ on:
|
||||
# Or the workflow itself is changed
|
||||
- ".github/workflows/web-crowdin.yml"
|
||||
schedule:
|
||||
# Run Mondays at ~6:00 AM IST
|
||||
#
|
||||
# [Note: Run workflow on specific days of the week]
|
||||
#
|
||||
# The last (5th) component of the cron syntax denotes the day of the
|
||||
@@ -16,7 +18,7 @@ on:
|
||||
# and FRI, this can be set to `2,5`.
|
||||
#
|
||||
# See also: [Note: Run workflow every 24 hours]
|
||||
- cron: "20 1 * * 2"
|
||||
- cron: "20 0 * * 1"
|
||||
# Also allow manually running the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
30
auth/assets/ca/lets-encrypt-r3.pem
Normal file
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
|
||||
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
|
||||
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
|
||||
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
|
||||
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
|
||||
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
|
||||
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
|
||||
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
|
||||
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
|
||||
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
|
||||
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
|
||||
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
|
||||
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
|
||||
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
|
||||
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
|
||||
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
|
||||
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
|
||||
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
|
||||
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
|
||||
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
|
||||
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
|
||||
nLRbwHOoq7hHwg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"icons": [
|
||||
{ "title": "1xBet",
|
||||
"altNames": ["1x", "1x bet", "1x-bet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "3Commas"
|
||||
},
|
||||
@@ -10,6 +14,10 @@
|
||||
{
|
||||
"title": "Airtable"
|
||||
},
|
||||
{
|
||||
"title": "airtm",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "Anycoin Direct",
|
||||
"slug": "anycoindirect"
|
||||
@@ -20,6 +28,12 @@
|
||||
{
|
||||
"title": "Bitfinex"
|
||||
},
|
||||
{
|
||||
"title": "bitget"
|
||||
},
|
||||
{
|
||||
"title": "Bitmart"
|
||||
},
|
||||
{
|
||||
"title": "BitMEX"
|
||||
},
|
||||
@@ -92,6 +106,10 @@
|
||||
{
|
||||
"title": "Crowdpear"
|
||||
},
|
||||
{
|
||||
"title": "crypto.com",
|
||||
"altNames": ["crypto"]
|
||||
},
|
||||
{
|
||||
"title": "DCS",
|
||||
"altNames": [
|
||||
@@ -102,6 +120,9 @@
|
||||
{
|
||||
"title": "DEGIRO"
|
||||
},
|
||||
{
|
||||
"title": "deriv"
|
||||
},
|
||||
{
|
||||
"title": "DirectAdmin"
|
||||
},
|
||||
@@ -171,6 +192,9 @@
|
||||
{
|
||||
"title": "Hivelocity"
|
||||
},
|
||||
{
|
||||
"title": "HTX"
|
||||
},
|
||||
{
|
||||
"title": "IceDrive",
|
||||
"slug": "Icedrive"
|
||||
@@ -317,6 +341,8 @@
|
||||
{
|
||||
"title": "Odido"
|
||||
},
|
||||
{ "title": "okx",
|
||||
"hex": "858585" },
|
||||
{
|
||||
"title": "Parsec"
|
||||
},
|
||||
@@ -534,6 +560,8 @@
|
||||
],
|
||||
"slug": "Yandex"
|
||||
},
|
||||
{ "title": "yahoo" },
|
||||
|
||||
{
|
||||
"title": "YNAB",
|
||||
"altNames": [
|
||||
@@ -543,4 +571,4 @@
|
||||
"hex": "3B5EDA"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
1
auth/assets/custom-icons/icons/1xBet.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.56 27.9"><defs><style>.cls-1{fill:#007acc;}.cls-2{fill:#002f5e;}</style></defs><title>logoo</title><g id="Слой_2" data-name="Слой 2"><g id="Layer_1" data-name="Layer 1"><path class="cls-1" d="M73.8,8.37C74.94,3.79,72.16,0,65.35,0L50.59,0,45.06,22.4l3.21,5.51h10.5c6.88,0,12.21-3.21,13.58-8.79.69-2.86-.11-4.86-1.91-5.86v-.07A7.78,7.78,0,0,0,73.8,8.37Zm-9,10.57c-.28,1.17-1.07,2.37-4.34,2.37h-6.7l1.17-4.8h6.67C64.83,16.5,65.07,17.73,64.76,18.94ZM66.14,8.52c-.24.9-.93,2-3.75,2h-6l1-3.9h6C66.24,6.6,66.38,7.52,66.14,8.52Z"/><polygon class="cls-1" points="83.09 17.1 96.53 17.1 98.06 10.5 84.71 10.5 85.75 6.6 98.97 6.6 100.5 0 78.8 0 71.92 27.9 96.5 27.9 98.11 21.3 82.1 21.3 83.09 17.1"/><polygon class="cls-1" points="102.38 0 100.84 6.6 108.87 6.6 103.6 27.9 112.03 27.9 117.31 6.6 125.91 6.6 127.56 0 102.38 0"/><path class="cls-2" d="M8.82,27.9H.32L4,13l.85-2.25L2.6,13,.1,15.53,0,8.09,8.82,0h6.87Z"/><path class="cls-2" d="M39.51,16.34,36.8,11.75,49.95,0H37.7l-5,4.8,0,0L15.74,20.35,7.6,27.9H19.19l8.71-7.77,2.93,5c1,1.26,2.41,2.79,8.39,2.79h7L39.52,16.33Z"/><path class="cls-2" d="M31.76,3.26l0-.06A7.69,7.69,0,0,0,25.12,0H16.07l6.75,11.48Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
auth/assets/custom-icons/icons/airtm.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-738.2 149.1 435.4 102.8" xml:space="preserve"><path d="M-612.2 149.1h-18.4v99.6h18.4zm-104.1 79 25.4-55 14 30.2zm79.3 20.7-17.9-38.7 17.4-11-8.9-15-15.9 10-17.4-37.6c-1.1-2.3-2.7-4.2-4.7-5.5s-4.4-2-6.7-1.9c-2.4.1-4.7.9-6.6 2.3s-3.4 3.3-4.3 5.5l-34.9 75.5-.1.2c-2.3 5.7-.8 12.2 3.8 16.2 4.5 3.9 10.8 4.2 15.6.9l48.2-30.3 13.7 29.5zm54.3-53.1h27.3c14.1 0 18.8-7.7 18.8-16.4s-4.7-15.9-18.7-15.9h-27.4zm30.9-46.6c26.2 0 34.6 14.6 34.6 30 0 11.6-5.8 23.7-21.5 27.9l24.7 41.7h-20.8l-23-39.1h-24.9v39.1H-601v-99.6zm40.1 15.4h35v84.2h18.4v-84.2h35v-15.4h-88.4zm123.9-15.4H-415v99.6h16.6v-72.1c0-4.5-.3-8.6-.7-12.1h.5c.5 2.7 1.9 7.9 3.2 11.6l27.3 72.5h17.3l27.3-72.5c1.5-3.8 3.1-9.4 3.5-11.6h.5c-.4 3.6-.7 8-.7 12.1v72.1h17.2v-99.6h-27.4l-25.8 69.5c-1.5 4.2-2.3 6.7-2.8 10.1h-.3c-.5-3-1.2-5.2-2.3-8.7-.1-.4-.3-.9-.4-1.4z" style="fill:#050505"/></svg>
|
||||
|
After Width: | Height: | Size: 892 B |
1
auth/assets/custom-icons/icons/bitget.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="40" height="40" rx="8.711" fill="#00f0ff"/><path d="M18.46 15.767h7.468l7.64 7.592c.498.493.5 1.297.006 1.793L23.775 35h-7.693l2.326-2.261 8.54-8.486-8.432-8.487" fill="#1b1b1b"/><path d="M21.53 24.234h-7.47l-7.64-7.592a1.267 1.267 0 0 1-.005-1.793L16.214 5h7.693l-2.326 2.261-8.54 8.486 8.432 8.487" fill="#1b1b1b"/></svg>
|
||||
|
After Width: | Height: | Size: 410 B |
6
auth/assets/custom-icons/icons/bitmart.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" class="logo" viewBox="0 0 500 500">
|
||||
<g fill="#fff">
|
||||
<path d="M307.382 358.988H153.698v13.428h153.684v-13.428zm-115.22 83.526H76.885v13.43h115.277v-13.43zm-76.984-83.468h-76.7v13.428h76.7v-13.428zm192.204-38.864H192.105v13.428h115.277v-13.428zm-153.797 0H76.942v13.428h76.643v-13.428zM307.38 146.585H115.236v13.428H307.38v-13.428zm-153.795-44.664h-76.7v13.428h76.7v-13.428z"/>
|
||||
<path d="M409.287 231.022v-.34A153.91 153.91 0 0 0 276.144.3h-160.91v19.232H276.6a134.58 134.58 0 0 1 106.653 53.207 134.574 134.574 0 0 1 22.564 117.033 117.661 117.661 0 0 0-63.274-132.566A117.668 117.668 0 0 0 291.45 45.42H153.7v19.232h137.92a98.265 98.265 0 0 1 93.597 128.078 76.986 76.986 0 0 0-13.255-66.509 76.985 76.985 0 0 0-60.713-30.218H191.764v19.402H310.68a57.81 57.81 0 0 1 50.186 86.316 154.248 154.248 0 0 0-53.714-9.673H153.528v19.23h153.625a134.624 134.624 0 0 1 132.234 109.474 115.392 115.392 0 0 0-112.32-89.559H115.179v19.062h212.175a96.05 96.05 0 0 1 62.678 23.55 96.055 96.055 0 0 1 32.058 58.781 76.87 76.87 0 0 0-75.505-62.986H115.292v19.233h231.236a57.637 57.637 0 1 1 0 115.276H76.885v19.232h269.7a76.872 76.872 0 0 0 75.504-62.988 96.047 96.047 0 0 1-95.021 82.163H230.34v19.23h96.727a115.44 115.44 0 0 0 110.838-83.697A134.673 134.673 0 0 1 307.44 480.466H115.463V499.7h191.69a153.629 153.629 0 0 0 149.901-190.401 153.642 153.642 0 0 0-47.482-78.388l-.285.112z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 500 500">
|
||||
<path fill="#182954" d="m75.705 269.386 12.606 10.812a40.902 40.902 0 0 1-8.642 8.853 53.365 53.365 0 0 1-13.599 7.73 45.769 45.769 0 0 1-16.998 3.094 49.02 49.02 0 0 1-25.212-6.466A45.84 45.84 0 0 1 6.72 275.84a50.83 50.83 0 0 1-6.212-25.287 52.621 52.621 0 0 1 3.525-19.394 49.28 49.28 0 0 1 10.2-16.022 46.603 46.603 0 0 1 15.44-10.812 49.626 49.626 0 0 1 19.969-3.938 45.9 45.9 0 0 1 23.51 5.48A49.016 49.016 0 0 1 88.308 219.5l-12.744 11.244A39.368 39.368 0 0 0 64.938 220.2a27.358 27.358 0 0 0-15.296-3.933 27.636 27.636 0 0 0-16.147 4.632 30.695 30.695 0 0 0-10.478 12.508 38.957 38.957 0 0 0-3.688 16.879 36.724 36.724 0 0 0 3.684 16.442 29.719 29.719 0 0 0 10.184 11.793 27.208 27.208 0 0 0 15.44 4.358c4.608.197 9.203-.62 13.456-2.391a27.765 27.765 0 0 0 8.214-5.622l5.381-5.481M93.275 264.047a35.477 35.477 0 0 1 4.535-17.71 34.84 34.84 0 0 1 12.748-12.929 39.497 39.497 0 0 1 18.838-4.778 39.497 39.497 0 0 1 18.838 4.778 34.846 34.846 0 0 1 12.749 12.928 36.889 36.889 0 0 1 4.532 17.709 36.891 36.891 0 0 1-4.532 17.708 36.519 36.519 0 0 1-13.365 13.153 36.875 36.875 0 0 1-18.181 4.837 36.88 36.88 0 0 1-18.203-4.756 36.513 36.513 0 0 1-13.424-13.092 35.479 35.479 0 0 1-4.535-17.707v-.141zm35.979 21.224a16.949 16.949 0 0 0 10.623-3.23c2.804-2.121 5-4.93 6.375-8.151a24.848 24.848 0 0 0 2.124-9.698 24.293 24.293 0 0 0-2.124-9.697 20.265 20.265 0 0 0-6.375-8.15 19.056 19.056 0 0 0-10.623-3.233 19.057 19.057 0 0 0-10.625 3.233 20.118 20.118 0 0 0-6.231 8.009 24.296 24.296 0 0 0-2.125 9.697 24.713 24.713 0 0 0 2.125 9.839 19.985 19.985 0 0 0 6.374 8.15 16.949 16.949 0 0 0 10.624 3.231M168.905 202.628h16.856v17.71h-16.856v-17.71zm0 28.11h16.856v66.758h-16.856v-66.758zM192.416 297.495V230.88h16.147l.42 7.589a35.937 35.937 0 0 1 7.505-5.905 23.656 23.656 0 0 1 12.749-3.094 24.38 24.38 0 0 1 10.396 1.612 24.22 24.22 0 0 1 8.726 5.836 29.047 29.047 0 0 1 6.66 20.097v40.477H238.02v-40.335a13.257 13.257 0 0 0-.76-5.278 13.337 13.337 0 0 0-2.78-4.561 12.19 12.19 0 0 0-4.164-2.694 12.27 12.27 0 0 0-4.902-.82 14.974 14.974 0 0 0-6.377 1.24 14.87 14.87 0 0 0-5.236 3.82 18.046 18.046 0 0 0-4.534 12.51v36.118l-16.851.004z"/>
|
||||
<path fill="#FA4A29" d="m463.25 246.618 29.754-44.007h-28.187l-15.44 24.596-15.883-24.596h-31.163l1.416 1.967-.993-.416a63.329 63.329 0 0 0-23.083-4.046 50.453 50.453 0 0 0-25.92 6.607 46.609 46.609 0 0 0-14.308 12.929 40.334 40.334 0 0 0-15.582-11.806 65.028 65.028 0 0 0-26.344-5.077h-36.686v94.727h36.544a64.026 64.026 0 0 0 26.344-5.202A41.612 41.612 0 0 0 339.3 280.63c3.87 5.299 8.846 9.709 14.59 12.928a51.44 51.44 0 0 0 25.777 6.325 55.023 55.023 0 0 0 24.646-5.34l-1.982 2.953h27.76l18.558-29.108 19.122 29.108h31.73l-36.252-50.878zm-147.452 21.624a25.772 25.772 0 0 1-8.902 5.504 25.916 25.916 0 0 1-10.376 1.523h-10.334v-50.573h10.338c3.62-.305 7.264.165 10.685 1.378a25.427 25.427 0 0 1 9.147 5.65 26.146 26.146 0 0 1 6.374 18.271 24.821 24.821 0 0 1-1.597 9.836 24.965 24.965 0 0 1-5.343 8.436l.008-.025zm101.549 6.911-12.04-11.228a38.572 38.572 0 0 1-10.197 9.149 27.09 27.09 0 0 1-13.6 2.952 25.509 25.509 0 0 1-13.314-3.372 22.838 22.838 0 0 1-8.8-9.415 29.459 29.459 0 0 1-3.118-13.63c-.091-4.623.929-9.2 2.975-13.353a23.258 23.258 0 0 1 8.642-9.415 25.653 25.653 0 0 1 13.738-3.513 24.798 24.798 0 0 1 12.748 3.23 32.061 32.061 0 0 1 9.639 8.733l12.606-12.508 18.415 26.28-17.694 26.09z"/>
|
||||
<path fill="#182954" d="m75.006 269.464 12.657 10.855a41.066 41.066 0 0 1-8.676 8.889 53.579 53.579 0 0 1-13.654 7.76 45.952 45.952 0 0 1-17.066 3.107 49.217 49.217 0 0 1-25.313-6.492 46.023 46.023 0 0 1-17.21-17.64A51.033 51.033 0 0 1-.49 250.556a52.832 52.832 0 0 1 3.538-19.472 49.477 49.477 0 0 1 10.242-16.086 46.79 46.79 0 0 1 15.5-10.855 49.825 49.825 0 0 1 20.05-3.954 46.083 46.083 0 0 1 23.605 5.503 49.212 49.212 0 0 1 15.215 13.685l-12.795 11.29a39.526 39.526 0 0 0-10.667-10.584 27.467 27.467 0 0 0-15.358-3.95 27.747 27.747 0 0 0-16.212 4.651 30.818 30.818 0 0 0-10.52 12.559 39.113 39.113 0 0 0-3.702 16.946 36.87 36.87 0 0 0 3.699 16.508 29.838 29.838 0 0 0 10.224 11.84 27.317 27.317 0 0 0 15.501 4.376 31.64 31.64 0 0 0 13.511-2.401 27.877 27.877 0 0 0 8.247-5.644l5.403-5.503m17.656-5.362a35.619 35.619 0 0 1 4.553-17.781 34.98 34.98 0 0 1 12.8-12.98 39.655 39.655 0 0 1 18.913-4.797 39.66 39.66 0 0 1 18.913 4.797 34.985 34.985 0 0 1 12.8 12.98 37.037 37.037 0 0 1 4.55 17.779 37.04 37.04 0 0 1-4.55 17.78 36.665 36.665 0 0 1-13.418 13.205 37.023 37.023 0 0 1-18.254 4.856 37.027 37.027 0 0 1-18.276-4.774A36.659 36.659 0 0 1 97.2 282.022a35.62 35.62 0 0 1-4.553-17.777v-.142zm36.123 21.31a17.017 17.017 0 0 0 10.666-3.244 20.199 20.199 0 0 0 6.4-8.184 24.947 24.947 0 0 0 2.133-9.736 24.391 24.391 0 0 0-2.133-9.736 20.347 20.347 0 0 0-6.4-8.183 19.133 19.133 0 0 0-10.666-3.245c-3.803 0-7.518 1.13-10.667 3.245a20.2 20.2 0 0 0-6.256 8.041 24.393 24.393 0 0 0-2.134 9.736 24.812 24.812 0 0 0 2.134 9.878 20.065 20.065 0 0 0 6.4 8.184 17.017 17.017 0 0 0 10.666 3.244m39.667-82.975h16.924v17.781H168.58v-17.781zm0 28.223h16.924v67.026H168.58V230.66zm23.605 67.025v-66.884h16.212l.42 7.62a36.08 36.08 0 0 1 7.537-5.929 23.751 23.751 0 0 1 12.8-3.106c3.556-.227 7.12.326 10.438 1.618a24.317 24.317 0 0 1 8.76 5.86 29.164 29.164 0 0 1 6.687 20.177v40.64h-17.067v-40.498a13.31 13.31 0 0 0-.763-5.298 13.39 13.39 0 0 0-2.792-4.58 12.239 12.239 0 0 0-4.18-2.705 12.32 12.32 0 0 0-4.921-.823c-2.2-.058-4.388.367-6.403 1.245a14.929 14.929 0 0 0-5.257 3.836 18.118 18.118 0 0 0-4.552 12.559v36.264l-16.919.004z"/>
|
||||
<path fill="#FA4A29" d="m464.104 246.605 29.874-44.184h-28.3l-15.502 24.695-15.946-24.695h-31.288l1.421 1.975-.997-.418a63.582 63.582 0 0 0-23.175-4.062 50.655 50.655 0 0 0-26.025 6.634 46.796 46.796 0 0 0-14.365 12.98 40.496 40.496 0 0 0-15.644-11.853 65.288 65.288 0 0 0-26.45-5.098h-36.833v95.107h36.691a64.283 64.283 0 0 0 26.45-5.223 41.778 41.778 0 0 0 15.643-11.71 45.958 45.958 0 0 0 14.647 12.98 51.646 51.646 0 0 0 25.882 6.35 55.244 55.244 0 0 0 24.744-5.361l-1.99 2.964h27.872l18.631-29.225 19.2 29.225H500.5l-36.396-51.081zm-148.042 21.71a25.875 25.875 0 0 1-8.938 5.526 26.02 26.02 0 0 1-10.417 1.53H286.33v-50.777h10.38a25.677 25.677 0 0 1 10.727 1.384 25.529 25.529 0 0 1 9.184 5.672 26.25 26.25 0 0 1 6.4 18.345 24.92 24.92 0 0 1-1.604 9.876 25.065 25.065 0 0 1-5.365 8.469l.009-.025zm101.955 6.939L405.93 263.98a38.727 38.727 0 0 1-10.237 9.185 27.198 27.198 0 0 1-13.654 2.965 25.611 25.611 0 0 1-13.368-3.386 22.93 22.93 0 0 1-8.836-9.453 29.577 29.577 0 0 1-3.13-13.685 29.036 29.036 0 0 1 2.987-13.406 23.352 23.352 0 0 1 8.676-9.452 25.756 25.756 0 0 1 13.793-3.528 24.898 24.898 0 0 1 12.8 3.244 32.19 32.19 0 0 1 9.677 8.767l12.657-12.558 18.488 26.386-17.765 26.194z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.3 KiB |
1
auth/assets/custom-icons/icons/crypto.com.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><circle cx="512" cy="512" r="512" style="fill:#002967"/><path d="M714.2 628.8 512 745.5 309.8 628.8V395.3L512 278.5l202.2 116.8zM512 256 290.3 384v256L512 768l221.7-128V384zm86.9 110.5H424.7l-20.2 88.8h215.4zM455.6 577.6v-59L404 485.8l-58.4 43.4 79.6 138.4H457l37.6-35V615zm113-108.9H455.8l19 49.6L469 574h43l43.4-.2-5.4-55.4zm51.6 16.7-51 33.2v59l-39 37.4v17.6l37.6 34.6h31.4l79.2-138z" style="fill:#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 479 B |
1
auth/assets/custom-icons/icons/deriv.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 216.86 72"><path fill="#FF444F" d="m43.472 2.271-3.715 21.06H26.86c-12.03 0-23.498 9.744-25.623 21.77l-.9 5.118C-1.777 62.246 6.25 71.99 18.281 71.99h10.755c8.768 0 17.122-7.095 18.664-15.86L57.605 0zm-9.15 51.872c-.475 2.707-2.914 4.911-5.622 4.911h-6.534c-5.408 0-9.026-4.388-8.077-9.803l.564-3.192c.958-5.405 6.119-9.803 11.526-9.803h11.298zm108.463 17.845 8.462-47.986h13.385l-8.462 47.986zm1.448-47.433-2.016 11.419c-6.341-1.97-12.883-1.343-14.893-.942L120.806 72h-13.394l8.032-45.52c4.357-1.803 15.055-5.462 28.789-1.925m-54.27-1.232h-10.42c-10.152 0-19.83 8.221-21.619 18.37L55.819 53.62c-1.79 10.15 4.981 18.37 15.135 18.37h22.163l2.273-12.895H74.562c-3.38 0-5.644-2.737-5.041-6.127l.07-.405h33.58l1.918-10.87c1.789-10.149-4.982-18.37-15.135-18.37zm1.69 17.342-.079.692H71.606l.109-.613c.602-3.38 3.687-6.354 7.077-6.354h7.8c3.351 0 5.615 2.925 5.061 6.275m111.81-16.663h13.394c-4.563 12.126-15.019 32.755-25.149 47.986h-13.394c-4.65-14.496-7.653-34.695-8.225-47.986h13.395c.241 4.335 2.183 20.417 4.399 31.651 6.077-10.93 12.777-25.269 15.569-31.651z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
6
auth/assets/custom-icons/icons/htx.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||
<g clip-path="url(#a)">
|
||||
<path fill="#fff" d="M301.399 153.471c1.48-73.53-40.157-137.614-61.84-153.005-.098-.1-2.022-1.16-1.874 1.726 0 .05-.05.05-.05.099-2.219 138.897-73.628 176.315-112.38 227.227-86.16 113.194-14.281 242.323 78.86 266.792 1.578.395 5.895 1.677 14.06 3.355 4.266.912 5.5-2.714 2.367-8.116-11.124-19.363-30.932-52.046-34.854-94.028-8.904-97.482 113.984-158.506 115.71-244.05z"/>
|
||||
<path fill="#008CD6" d="M348.339 200.56c-.74-.543-1.776-.494-1.875.444-1.973 17.66-20.25 54.315-44.325 88.577-81.005 115.513-40.207 167.904-8.51 204.262 5.846 6.734 8.756 5.23 11.84.444 2.86-4.563 7.227-10.36 25.949-19.215 2.91-1.381 73.604-38.923 81.276-124.393 7.4-82.681-45.633-134.974-64.355-150.12z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 790 B |
110
auth/assets/custom-icons/icons/okx.svg
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="157.42708mm"
|
||||
height="44.185417mm"
|
||||
viewBox="0 0 157.42708 44.185417"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="okx logo.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="567.26578"
|
||||
inkscape:cy="219.28838"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="70"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-62.058587,-90.445746)">
|
||||
<g
|
||||
style="fill:#000000"
|
||||
id="g886"
|
||||
transform="matrix(0.39972707,0,0,0.34817986,61.931647,90.445746)">
|
||||
<path
|
||||
id="path839"
|
||||
d="M 115.822,0 H 2.94268 C 2.24645,0 1.57875,0.297103 1.08644,0.825953 0.594137,1.3548 0.317566,2.07208 0.317566,2.81999 V 124.079 c 0,0.748 0.276571,1.466 0.768874,1.995 0.49231,0.528 1.16001,0.825 1.85624,0.825 H 115.822 c 0.697,0 1.364,-0.297 1.857,-0.825 0.492,-0.529 0.769,-1.247 0.769,-1.995 V 2.81999 c 0,-0.74791 -0.277,-1.46519 -0.769,-1.994037 C 117.186,0.297103 116.519,0 115.822,0 Z M 79.0709,81.7797 c 0,0.7479 -0.2766,1.4651 -0.7689,1.994 -0.4923,0.5288 -1.16,0.8259 -1.8562,0.8259 H 42.3193 c -0.6962,0 -1.3639,-0.2971 -1.8562,-0.8259 -0.4923,-0.5289 -0.7689,-1.2461 -0.7689,-1.994 V 45.1198 c 0,-0.7479 0.2766,-1.4652 0.7689,-1.994 0.4923,-0.5289 1.16,-0.826 1.8562,-0.826 h 34.1265 c 0.6962,0 1.3639,0.2971 1.8562,0.826 0.4923,0.5288 0.7689,1.2461 0.7689,1.994 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path841"
|
||||
d="m 352.131,42.305 h -34.127 c -1.449,0 -2.625,1.2625 -2.625,2.82 v 36.6598 c 0,1.5574 1.176,2.82 2.625,2.82 h 34.127 c 1.45,0 2.625,-1.2626 2.625,-2.82 V 45.125 c 0,-1.5575 -1.175,-2.82 -2.625,-2.82 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path843"
|
||||
d="m 312.763,0.00204468 h -34.126 c -1.45,0 -2.625,1.26255532 -2.625,2.81998532 V 39.4819 c 0,1.5574 1.175,2.82 2.625,2.82 h 34.126 c 1.45,0 2.626,-1.2626 2.626,-2.82 V 2.82203 c 0,-1.55743 -1.176,-2.81998532 -2.626,-2.81998532 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path845"
|
||||
d="m 391.529,0.00204468 h -34.127 c -1.449,0 -2.625,1.26255532 -2.625,2.81998532 V 39.4819 c 0,1.5574 1.176,2.82 2.625,2.82 h 34.127 c 1.45,0 2.625,-1.2626 2.625,-2.82 V 2.82203 c 0,-1.55743 -1.175,-2.81998532 -2.625,-2.81998532 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path847"
|
||||
d="m 312.763,84.6038 h -34.126 c -1.45,0 -2.625,1.2625 -2.625,2.8199 v 36.6603 c 0,1.557 1.175,2.82 2.625,2.82 h 34.126 c 1.45,0 2.626,-1.263 2.626,-2.82 V 87.4237 c 0,-1.5574 -1.176,-2.8199 -2.626,-2.8199 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path849"
|
||||
d="m 391.529,84.6038 h -34.127 c -1.449,0 -2.625,1.2625 -2.625,2.8199 v 36.6603 c 0,1.557 1.176,2.82 2.625,2.82 h 34.127 c 1.45,0 2.625,-1.263 2.625,-2.82 V 87.4237 c 0,-1.5574 -1.175,-2.8199 -2.625,-2.8199 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path851"
|
||||
d="m 253.651,0.00204468 h -34.126 c -1.45,0 -2.626,1.26255532 -2.626,2.81998532 V 39.4819 c 0,1.5574 1.176,2.82 2.626,2.82 h 34.126 c 1.45,0 2.625,-1.2626 2.625,-2.82 V 2.82203 c 0,-1.55743 -1.175,-2.81998532 -2.625,-2.81998532 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path853"
|
||||
d="m 253.651,84.6038 h -34.126 c -1.45,0 -2.626,1.2625 -2.626,2.8199 v 36.6603 c 0,1.557 1.176,2.82 2.626,2.82 h 34.126 c 1.45,0 2.625,-1.263 2.625,-2.82 V 87.4237 c 0,-1.5574 -1.175,-2.8199 -2.625,-2.8199 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path855"
|
||||
d="m 216.888,45.0881 c 0,-0.7479 -0.277,-1.4652 -0.769,-1.994 -0.492,-0.5289 -1.16,-0.826 -1.856,-0.826 H 177.511 V 2.81999 c 0,-0.74791 -0.277,-1.46519 -0.769,-1.994037 C 176.25,0.297103 175.582,0 174.886,0 H 140.76 c -0.697,0 -1.364,0.297103 -1.857,0.825953 -0.492,0.528847 -0.769,1.246127 -0.769,1.994037 V 124.016 c 0,0.748 0.277,1.465 0.769,1.994 0.493,0.529 1.16,0.826 1.857,0.826 h 34.126 c 0.696,0 1.364,-0.297 1.856,-0.826 0.492,-0.529 0.769,-1.246 0.769,-1.994 V 84.5679 h 36.752 c 0.696,0 1.364,-0.2971 1.856,-0.8259 0.492,-0.5289 0.769,-1.2462 0.769,-1.9941 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
1
auth/assets/custom-icons/icons/yahoo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><circle cx="512" cy="512" r="512" style="fill:#6001d2"/><path d="M256 390.61h101.45l59.06 151 59.83-151H575L426.38 748.15H327l40.66-94.74Zm332.7 143.54a61.36 61.36 0 1 0 61.37 61.35 61.36 61.36 0 0 0-61.37-61.35M768 275.85H657.83l-98.09 235.67h110.55Z" style="fill:#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 344 B |
@@ -1,10 +1,8 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/core/win_http_client.dart';
|
||||
import 'package:ente_auth/events/endpoint_updated_event.dart';
|
||||
import 'package:ente_auth/utils/package_info_util.dart';
|
||||
import 'package:ente_auth/utils/platform_util.dart';
|
||||
@@ -52,19 +50,6 @@ class Network {
|
||||
},
|
||||
),
|
||||
);
|
||||
if (Platform.isWindows) {
|
||||
final customHttpClient = windowsHttpClient();
|
||||
_enteDio.httpClientAdapter = IOHttpClientAdapter(
|
||||
createHttpClient: () {
|
||||
return customHttpClient;
|
||||
},
|
||||
);
|
||||
_dio.httpClientAdapter = IOHttpClientAdapter(
|
||||
createHttpClient: () {
|
||||
return customHttpClient;
|
||||
},
|
||||
);
|
||||
}
|
||||
_setupInterceptors(endpoint);
|
||||
|
||||
Bus.instance.on<EndpointUpdatedEvent>().listen((event) {
|
||||
|
||||
1
auth/lib/l10n/arb/app_ca.arb
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -9,7 +9,7 @@
|
||||
"onBoardingBody": "Sichern Sie Ihre 2FA-Codes",
|
||||
"onBoardingGetStarted": "Los geht's",
|
||||
"setupFirstAccount": "Ihr erstes Konto einrichten",
|
||||
"importScanQrCode": "Scannen eines QR-Codes",
|
||||
"importScanQrCode": "QR-Code scannen",
|
||||
"qrCode": "QR-Code",
|
||||
"importEnterSetupKey": "Einen Setup-Schlüssel eingeben",
|
||||
"importAccountPageTitle": "Kontodaten eingeben",
|
||||
@@ -31,7 +31,7 @@
|
||||
"timeBasedKeyType": "Zeitbasiert (TOTP)",
|
||||
"counterBasedKeyType": "Zählerbasiert (HOTP)",
|
||||
"saveAction": "Speichern",
|
||||
"nextTotpTitle": "Weiter",
|
||||
"nextTotpTitle": "Nächster Code",
|
||||
"deleteCodeTitle": "Code löschen?",
|
||||
"deleteCodeMessage": "Sind Sie sicher, dass Sie diesen Code löschen wollen? Diese Aktion ist unumkehrbar.",
|
||||
"viewLogsAction": "Protokolle anzeigen",
|
||||
@@ -139,7 +139,7 @@
|
||||
"inFamilyPlanMessage": "Sie haben einen Familien-Plan!",
|
||||
"swipeHint": "Wischen Sie nach links, um Codes zu bearbeiten oder zu entfernen",
|
||||
"scan": "Scannen",
|
||||
"scanACode": "Scannen eines Codes",
|
||||
"scanACode": "Scan einen Code",
|
||||
"verify": "Überprüfen Sie",
|
||||
"verifyEmail": "E-Mail-Adresse verifizieren",
|
||||
"enterCodeHint": "Geben Sie den 6-stelligen Code \naus Ihrer Authentifikator-App ein.",
|
||||
@@ -263,6 +263,8 @@
|
||||
"exportLogs": "Logs exportieren",
|
||||
"enterYourRecoveryKey": "Wiederherstellungsschlüssel eingeben",
|
||||
"tempErrorContactSupportIfPersists": "Etwas ist schiefgelaufen. Bitte versuchen sie es später noch einmal. Sollte der Fehler weiter bestehen, kontaktieren sie unser Supportteam.",
|
||||
"networkHostLookUpErr": "Ente ist im Moment nicht erreichbar. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. Sollte das Problem bestehen bleiben, wenden Sie sich bitte an den Support.",
|
||||
"networkConnectionRefusedErr": "Ente ist im Moment nicht erreichbar. Bitte versuchen Sie es später erneut. Sollte das Problem bestehen bleiben, wenden Sie sich bitte an den Support.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Etwas ist schiefgelaufen. Bitte versuchen sie es später noch einmal. Sollte der Fehler weiter bestehen, kontaktieren sie unser Supportteam.",
|
||||
"about": "Über uns",
|
||||
"weAreOpenSource": "Wir sind Opensource!",
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"codeIssuerHint": "Emisor",
|
||||
"codeSecretKeyHint": "Llave Secreta",
|
||||
"codeAccountHint": "Cuenta (tu@dominio.com)",
|
||||
"codeTagHint": "Marcado",
|
||||
"accountKeyType": "Tipo de llave",
|
||||
"sessionExpired": "La sesión ha expirado",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -77,12 +79,14 @@
|
||||
"data": "Datos",
|
||||
"importCodes": "Importar códigos",
|
||||
"importTypePlainText": "Texto sin formato",
|
||||
"importTypeEnteEncrypted": "Exportación cifrada Ente",
|
||||
"passwordForDecryptingExport": "Contraseña para descifrar exportación",
|
||||
"passwordEmptyError": "La contraseña no puede estar vacía",
|
||||
"importFromApp": "Importar códigos de {appName}",
|
||||
"importGoogleAuthGuide": "Exportar tus cuentas desde Google Authenticator a un código QR usando la opción \"Transferir Cuentas\". A continuación, usando otro dispositivo, escanee el código QR.\n\nConsejo: Puede usar la webcam de su portátil para tomar una foto del código QR.",
|
||||
"importSelectJsonFile": "Seleccione el archivo JSON",
|
||||
"importSelectAppExport": "Seleccione el archivo de exportación de {appName}",
|
||||
"importEnteEncGuide": "Seleccione el archivo JSON cifrado exportado desde Ente",
|
||||
"importRaivoGuide": "Utilice la opción \"Exportar códigos a un archivo de Zip\" en la configuración de Raivo.\n\nExtraiga el archivo zip e importe el archivo JSON.",
|
||||
"importBitwardenGuide": "Use la opción \"Exportar caja fuerte\" dentro del menú Herramientas de Bitwarden e importe el fichero JSON no crifrado.",
|
||||
"importAegisGuide": "Utilice la opción \"Exportar la bóveda\" en ajustes de Aegis.\n\nSi tu bóveda es cifrada, necesitara entrar contraseña de bóveda para descifrar la bóveda.",
|
||||
@@ -119,12 +123,15 @@
|
||||
"oops": "Ups",
|
||||
"suggestFeatures": "Sugerir funcionalidades",
|
||||
"faq": "Preguntas Frecuentes",
|
||||
"faq_q_1": "¿Qué tan seguro es Auth?",
|
||||
"faq_a_1": "Todos los códigos que copia de seguridad vía Ente se almacenan cifrados de extremo a extremo. Esto significa que solo usted puede acceder a sus códigos. Nuestras aplicaciones son de código abierto y nuestra criptografía ha sido auditada externamente.",
|
||||
"faq_q_2": "¿Puedo acceder a mis códigos en el escritorio?",
|
||||
"faq_a_2": "Puede acceder a tus códigos en la web en auth.ente.io.",
|
||||
"faq_q_3": "¿Cómo puedo borrar códigos?",
|
||||
"faq_a_3": "Puede eliminar un código deslizando a la izquierda en ese elemento.",
|
||||
"faq_q_4": "¿Cómo puedo apoyar este proyecto?",
|
||||
"faq_a_4": "Puedes apoyar el desarrollo de este proyecto suscribiéndote a nuestra app de Fotos en ente.io.",
|
||||
"faq_q_5": "Cómo puedo habilitar bloqueo FaceID en Ente Auth",
|
||||
"faq_a_5": "Puede activar el bloqueo FaceID en Ajustes → Seguridad → Pantalla de bloqueo.",
|
||||
"somethingWentWrongMessage": "Algo ha ido mal, por favor, prueba otra vez",
|
||||
"leaveFamily": "Dejar plan familiar",
|
||||
@@ -151,6 +158,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"invalidQRCode": "Código QR no válido",
|
||||
"noRecoveryKeyTitle": "¿Sin clave de recuperación?",
|
||||
"enterEmailHint": "Introduce tu dirección de correo electrónico",
|
||||
"invalidEmailTitle": "Dirección de correo electrónico no válida",
|
||||
@@ -195,6 +203,8 @@
|
||||
"saveKey": "Guardar Clave",
|
||||
"save": "Guardar",
|
||||
"send": "Enviar",
|
||||
"saveOrSendDescription": "¿Desea guardar esto en el almacenamiento (carpeta Descargas por defecto) o enviarlo a otras aplicaciones?",
|
||||
"saveOnlyDescription": "¿Desea guardar esto en el almacenamiento (carpeta Descargas por defecto)?",
|
||||
"back": "Atrás",
|
||||
"createAccount": "Crear cuenta",
|
||||
"passwordStrength": "Fortaleza de la contraseña: {passwordStrengthValue}",
|
||||
@@ -253,12 +263,15 @@
|
||||
"exportLogs": "Exportar registros",
|
||||
"enterYourRecoveryKey": "Introduzca su clave de recuperación",
|
||||
"tempErrorContactSupportIfPersists": "Parece que algo salió mal. Por favor, vuelve a intentarlo después de algún tiempo. Si el error persiste, ponte en contacto con nuestro equipo de soporte.",
|
||||
"networkHostLookUpErr": "No se puede conectar a Ente. Por favor, comprueba tu configuración de red y ponte en contacto con el soporte técnico si el error persiste.",
|
||||
"networkConnectionRefusedErr": "No se puede conectar a Ente. Por favor, vuelve a intentarlo pasado un tiempo. Si el error persiste, ponte en contacto con el soporte técnico.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Parece que algo salió mal. Por favor, vuelve a intentarlo después de algún tiempo. Si el error persiste, ponte en contacto con nuestro equipo de soporte.",
|
||||
"about": "Acerca de",
|
||||
"weAreOpenSource": "¡Somos de código abierto!",
|
||||
"privacy": "Privacidad",
|
||||
"terms": "Términos",
|
||||
"checkForUpdates": "Comprobar actualizaciones",
|
||||
"checkStatus": "Comprobar estado",
|
||||
"downloadUpdate": "Descargar",
|
||||
"criticalUpdateAvailable": "Actualización crítica disponible",
|
||||
"updateAvailable": "Actualizacion disponible",
|
||||
@@ -342,6 +355,7 @@
|
||||
"deleteCodeAuthMessage": "Autenticar para borrar código",
|
||||
"showQRAuthMessage": "Autenticar para mostrar código QR",
|
||||
"confirmAccountDeleteTitle": "Confirmar eliminación de la cuenta",
|
||||
"confirmAccountDeleteMessage": "Esta cuenta está vinculada a otras aplicaciones de Ente, si utilizas alguna. Se programará la eliminación de los datos cargados en todas las aplicaciones de Ente, y tu cuenta se eliminará permanentemente.",
|
||||
"androidBiometricHint": "Verificar identidad",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
@@ -402,7 +416,31 @@
|
||||
"doNotSignOut": "No cerrar la sesión",
|
||||
"hearUsWhereTitle": "¿Cómo conoció Ente? (opcional)",
|
||||
"hearUsExplanation": "No rastreamos las aplicaciones instaladas. ¡Nos ayudaría si nos dijera dónde nos encontró!",
|
||||
"recoveryKeySaved": "¡Clave de recuperación guardada en la carpeta Descargas!",
|
||||
"waitingForBrowserRequest": "Esperando la solicitud del navegador...",
|
||||
"waitingForVerification": "Esperando verificación...",
|
||||
"passkey": "Llave de acceso",
|
||||
"passKeyPendingVerification": "La verificación todavía está pendiente",
|
||||
"loginSessionExpired": "La sesión ha expirado",
|
||||
"loginSessionExpiredDetails": "Tu sesión ha expirado. Por favor, vuelve a iniciar sesión.",
|
||||
"developerSettingsWarning": "¿Estás seguro de que quieres modificar los ajustes de desarrollador?",
|
||||
"developerSettings": "Ajustes de desarrollador"
|
||||
"developerSettings": "Ajustes de desarrollador",
|
||||
"serverEndpoint": "Punto final del servidor",
|
||||
"invalidEndpoint": "Punto final no válido",
|
||||
"invalidEndpointMessage": "Lo sentimos, el punto final introducido no es válido. Por favor, introduce un punto final válido y vuelve a intentarlo.",
|
||||
"endpointUpdatedMessage": "Punto final actualizado con éxito",
|
||||
"customEndpoint": "Conectado a {endpoint}",
|
||||
"pinText": "Fijar",
|
||||
"unpinText": "Desanclar",
|
||||
"pinnedCodeMessage": "{code} ha sido anclado",
|
||||
"unpinnedCodeMessage": "{code} ha sido desanclado",
|
||||
"tags": "Etiquetas",
|
||||
"createNewTag": "Crear Nueva Etiqueta",
|
||||
"tag": "Etiqueta",
|
||||
"create": "Crear",
|
||||
"editTag": "Editar Etiqueta",
|
||||
"deleteTagTitle": "¿Eliminar etiqueta?",
|
||||
"deleteTagMessage": "¿Estás seguro de que quieres eliminar esta etiqueta? Esta acción es irreversible.",
|
||||
"somethingWentWrongParsingCode": "No se han podido analizar los códigos {x}.",
|
||||
"updateNotAvailable": "Actualización no disponible"
|
||||
}
|
||||
118
auth/lib/l10n/arb/app_gu.arb
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"account": "ખાતું",
|
||||
"unlock": "અનલોક કરો",
|
||||
"recoveryKey": "પુનઃપ્રાપ્તિ ચાવી",
|
||||
"onBoardingBody": "તમારા 2FA કોડનો સુરક્ષિત રીતે બેકઅપ લો",
|
||||
"onBoardingGetStarted": "શરૂ કરો",
|
||||
"setupFirstAccount": "તમારું પ્રથમ એકાઉન્ટ સેટ કરો",
|
||||
"importScanQrCode": "QR કોડ સ્કેન કરો",
|
||||
"qrCode": "QR કોડ",
|
||||
"importEnterSetupKey": "સેટઅપ કી દાખલ કરો",
|
||||
"importAccountPageTitle": "એકાઉન્ટ વિગતો દાખલ કરો",
|
||||
"secretCanNotBeEmpty": "રહસ્ય ખાલી ન હોઈ શકે",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "રજૂકર્તા અને ખાતું બંને ખાલી હોઈ શકતા નથી",
|
||||
"incorrectDetails": "ખોટી વિગતો",
|
||||
"pleaseVerifyDetails": "કૃપા કરીને વિગતો ચકાસો અને ફરી પ્રયાસ કરો",
|
||||
"codeIssuerHint": "રજૂકર્તા",
|
||||
"codeSecretKeyHint": "ગુપ્ત ચાવી",
|
||||
"codeAccountHint": "ખાતું (you@domain.com)",
|
||||
"codeTagHint": "ચિઠ્ઠી",
|
||||
"accountKeyType": "ચાવી નો પ્રકાર",
|
||||
"sessionExpired": "સત્ર સમાપ્ત થયુ",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "કૃપા કરીને ફરી લોગિન કરો",
|
||||
"loggingOut": "લૉગ આઉટ થઈ રહ્યું છે...",
|
||||
"timeBasedKeyType": "સમય આધારિત (TOTP)",
|
||||
"counterBasedKeyType": "ગણતરી આધારિત (HOTP)",
|
||||
"saveAction": "સાચવો",
|
||||
"nextTotpTitle": "આગળ",
|
||||
"deleteCodeTitle": "કોડ કાઢી નાખીએ?",
|
||||
"deleteCodeMessage": "શું તમે ખરેખર આ કોડ કાઢી નાખવા માંગો છો? આ ક્રિયા બદલી શકાય તેવી નથી.",
|
||||
"viewLogsAction": "લોગ જુઓ",
|
||||
"sendLogsDescription": "આ તમારી સમસ્યાને ડીબગ કરવામાં અમને મદદ કરવા માટે અમને લોગ મોકલશે. જ્યારે સંવેદનશીલ માહિતી લૉગ ન થાય તેની ખાતરી કરવા માટે અમે સાવચેતી રાખીએ છીએ, અમે તમને આ લોગ મોકલતા પહેલા જોવા માટે પ્રોત્સાહિત કરીએ છીએ.",
|
||||
"preparingLogsTitle": "લૉગ્સ તૈયાર કરી રહ્યાં છીએ...",
|
||||
"emailLogsTitle": "લોગ ઇમેઇલ કરો",
|
||||
"emailLogsMessage": "કૃપા કરીને આને {email} લોગ મોકલો",
|
||||
"@emailLogsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"copyEmailAction": "ઈમેલ કોપી કરો",
|
||||
"exportLogsAction": "લોગ નિકાસ કરો",
|
||||
"reportABug": "બગની જાણ કરો",
|
||||
"crashAndErrorReporting": "ભાંગી પડવાની અને ભૂલની જાણ કરવી",
|
||||
"reportBug": "બગની જાણ કરો",
|
||||
"emailUsMessage": "કૃપા કરીને અમને {email} ઇમેઇલ કરો",
|
||||
"@emailUsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contactSupport": "સહાયતા માટે સંપર્ક કરો",
|
||||
"rateUsOnStore": "{storeName} પર અમને રેટ કરો",
|
||||
"blog": "બ્લોગ",
|
||||
"merchandise": "વેપારી વસ્તુઓ",
|
||||
"verifyPassword": "પાસવર્ડ ચકાસો",
|
||||
"pleaseWait": "કૃપા કરીને રાહ જુવો...",
|
||||
"generatingEncryptionKeysTitle": "એન્ક્રિપ્શન ચાવીઓ જનરેટ કરી રહ્યાં છીએ...",
|
||||
"recreatePassword": "પાસવર્ડ ફરીથી બનાવો",
|
||||
"recreatePasswordMessage": "વર્તમાન ઉપકરણ તમારા પાસવર્ડને ચકાસવા માટે પૂરતું શક્તિશાળી નથી, તેથી અમારે તેને તમામ ઉપકરણો સાથે કામ કરે તે રીતે એકવાર ફરીથી બનાવવાની જરૂર છે.\n\nકૃપા કરીને તમારી પુનઃપ્રાપ્તિ ચાવીનો ઉપયોગ કરીને લૉગિન કરો અને તમારો પાસવર્ડ ફરીથી બનાવો (જો તમે ઈચ્છો તો તમે તે જ ફરી ઉપયોગ કરી શકો છો).",
|
||||
"useRecoveryKey": "પુનઃપ્રાપ્તિ કીનો ઉપયોગ કરો",
|
||||
"incorrectPasswordTitle": "ખોટો પાસવર્ડ",
|
||||
"welcomeBack": "ફરી તમારુ સ્વાગત છે!",
|
||||
"madeWithLoveAtPrefix": " ખાતે ❤️ સાથે બનાવેલ છે",
|
||||
"supportDevs": "અમને સમર્થન આપવા માટે <bold-green>ente</bold-green> પર સબ્સ્ક્રાઇબ કરો",
|
||||
"supportDiscount": "પ્રથમ વર્ષે મા 10% છૂટ મેળવવા માટે કૂપન કોડ \"AUTH\" નો ઉપયોગ કરો",
|
||||
"changeEmail": "ઈ - મેઈલ બદલો",
|
||||
"changePassword": "પાસવર્ડ બદલો",
|
||||
"data": "માહિતી",
|
||||
"importCodes": "કોડ્સ આયાત કરો",
|
||||
"importTypePlainText": "સાદુ લખાણ",
|
||||
"importTypeEnteEncrypted": "એન્ટે એન્ક્રિપ્ટેડ નિકાસ",
|
||||
"passwordForDecryptingExport": "નિકાસને ડિક્રિપ્ટ કરવા માટે પાસવર્ડ",
|
||||
"passwordEmptyError": "પાસવર્ડ ખાલી ન હોઈ શકે",
|
||||
"importFromApp": "{appName} થી કોડ્સ આયાત કરો",
|
||||
"selectFile": "ફાઇલ પસંદ કરો",
|
||||
"ok": "સારું",
|
||||
"cancel": "રદ કરો",
|
||||
"yes": "હા",
|
||||
"no": "ના",
|
||||
"email": "ઇમેઇલ",
|
||||
"support": "સહાય",
|
||||
"general": "સામાન્ય",
|
||||
"delete": "કાઢી નાખો",
|
||||
"enterPassword": "પાસવર્ડ દાખલ કરો",
|
||||
"encrypted": "એનક્રિપ્ટ થયેલ",
|
||||
"plainText": "સાદુ લખાણ",
|
||||
"passwordToEncryptExport": "નિકાસને એન્ક્રિપ્ટ કરવા માટે પાસવર્ડ",
|
||||
"export": "નિકાસ કરો",
|
||||
"singIn": "સાઇન ઇન કરો",
|
||||
"androidBiometricSuccess": "સફળતા",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "રદ કરો",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "પ્રમાણીકરણ જરૂરી છે",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"goToSettings": "સેટિંગ માં જાઓ",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"iOSOkButton": "બરાબર",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"tags": "ચિઠ્ઠી"
|
||||
}
|
||||
1
auth/lib/l10n/arb/app_hi.arb
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -1,22 +1,85 @@
|
||||
{
|
||||
"account": "Akun",
|
||||
"unlock": "Buka",
|
||||
"recoveryKey": "Kunci pemulihan",
|
||||
"onBoardingBody": "Cadangkan kode 2FA kamu dengan aman",
|
||||
"onBoardingGetStarted": "Mulai",
|
||||
"setupFirstAccount": "Siapkan akun pertama kamu",
|
||||
"importScanQrCode": "Pindai Kode QR",
|
||||
"qrCode": "Kode QR",
|
||||
"importEnterSetupKey": "Masukkan kunci penyiapan",
|
||||
"importAccountPageTitle": "Masukkan detail akun",
|
||||
"incorrectDetails": "Rincian salah",
|
||||
"pleaseVerifyDetails": "Periksa kembali data kamu dan coba lagi",
|
||||
"codeIssuerHint": "Penerbit",
|
||||
"codeSecretKeyHint": "Kunci Rahasia",
|
||||
"codeAccountHint": "Akun (kamu@domain.com)",
|
||||
"codeTagHint": "Tag",
|
||||
"sessionExpired": "Sesi berakhir",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "Silakan masuk akun lagi",
|
||||
"loggingOut": "Mengeluarkan akun...",
|
||||
"timeBasedKeyType": "Berbasis waktu (TOTP)",
|
||||
"saveAction": "Simpan",
|
||||
"nextTotpTitle": "berikutnya",
|
||||
"deleteCodeTitle": "Hapus kode?",
|
||||
"deleteCodeMessage": "Apakah kamu yakin ingin menghapus kode ini? Tindakan ini tidak dapat dikembalikan ke semula.",
|
||||
"viewLogsAction": "Lihat log",
|
||||
"sendLogsDescription": "Langkah ini akan mengirimkan log untuk membantu kami menganalisa masalah kamu. Meskipun kami melakukan tindakan pencegahan untuk memastikan bahwa informasi sensitif tidak dicatat, kami menganjurkan kamu untuk melihat log ini sebelum membagikannya.",
|
||||
"preparingLogsTitle": "Menyiapkan log...",
|
||||
"copyEmailAction": "Salin email",
|
||||
"exportLogsAction": "Ekspor log",
|
||||
"reportABug": "Laporkan bug",
|
||||
"reportBug": "Laporkan bug",
|
||||
"contactSupport": "Hubungi dukungan",
|
||||
"rateUsOnStore": "Nilai kami di {storeName}",
|
||||
"blog": "Blog",
|
||||
"verifyPassword": "Verifikasi sandi",
|
||||
"pleaseWait": "Harap tunggu...",
|
||||
"generatingEncryptionKeysTitle": "Membuat kunci enkripsi...",
|
||||
"recreatePassword": "Buat kembali katasandi",
|
||||
"recreatePasswordMessage": "Perangkat ini tidak cukup kuat untuk memverifikasi kata sandi kamu, jadi kami perlu membuat ulang kata sandi kamu sekali lagi dengan cara yang dapat digunakan di semua perangkat.\n\nSilahkan masuk menggunakan kunci pemulihan dan buat ulang kata sandi kamu (Kamu dapat menggunakan kata sandi yang sama lagi jika mau).",
|
||||
"useRecoveryKey": "Gunakan kunci pemulihan",
|
||||
"incorrectPasswordTitle": "Kata sandi salah",
|
||||
"welcomeBack": "Selamat datang kembali!",
|
||||
"madeWithLoveAtPrefix": "dibuat dengan ❤️ di ",
|
||||
"supportDevs": "Berlangganan <bold-green>ente</bold-green> untuk mendukung kami",
|
||||
"supportDiscount": "Gunakan kode kupon \"AUTH\" untuk mendapatkan potongan 10% pada tahun pertamamu",
|
||||
"changeEmail": "Ubah email",
|
||||
"changePassword": "Ubah sandi",
|
||||
"data": "Data",
|
||||
"importCodes": "Impor kode",
|
||||
"importTypePlainText": "Teks biasa",
|
||||
"passwordForDecryptingExport": "Kata sandi untuk mendekripsi ekspor",
|
||||
"passwordEmptyError": "Kata sandi tidak boleh kosong",
|
||||
"importFromApp": "Impor kode dari {appName}",
|
||||
"importSelectJsonFile": "Pilih File JSON",
|
||||
"importSelectAppExport": "Pilih file ekspor dari {appName}",
|
||||
"selectFile": "Pilih file",
|
||||
"emailVerificationToggle": "Verifikasi email",
|
||||
"emailVerificationEnableWarning": "Untuk menghindari akun kamu terkunci, pastikan untuk menyimpan salinan 2FA email kamu di luar Ente Auth sebelum mengaktifkan verifikasi email.",
|
||||
"ok": "Oke",
|
||||
"cancel": "Batal",
|
||||
"email": "Email",
|
||||
"support": "Dukungan",
|
||||
"general": "Umum",
|
||||
"settings": "Pengaturan",
|
||||
"newUser": "Baru di Ente",
|
||||
"delete": "Hapus",
|
||||
"enterYourPasswordHint": "Masukkan sandi kamu",
|
||||
"suggestFeatures": "Sarankan fitur",
|
||||
"faq": "Tanya Jawab Umum",
|
||||
"faq_q_1": "Seberapa aman Auth itu?",
|
||||
"faq_a_1": "Semua kode yang kamu cadangkan melalui Auth disimpan menggunakan enkripsi end-to-end. Jadi hanya kamu yang dapat mengaksesnya. Aplikasi kami bersifat open source dan kriptografi kami telah diaudit oleh eksternal.",
|
||||
"faq_q_2": "Bisakah saya mengakses kode saya di desktop?",
|
||||
"faq_a_2": "Kamu dapat mengakses kodenya melalui web auth.ente.io.",
|
||||
"scan": "Pindai",
|
||||
"scanACode": "Pindai kode",
|
||||
"verify": "Verifikasi",
|
||||
"verifyEmail": "Verifikasi email",
|
||||
"enterCodeHint": "Masukkan kode 6 angka dari\napp autentikator kamu",
|
||||
"createNewAccount": "Buat akun baru",
|
||||
"confirmPassword": "Konfirmasi sandi",
|
||||
"selectLanguage": "Pilih bahasa",
|
||||
|
||||
@@ -263,6 +263,8 @@
|
||||
"exportLogs": "Esporta log",
|
||||
"enterYourRecoveryKey": "Inserisci la tua chiave di recupero",
|
||||
"tempErrorContactSupportIfPersists": "Sembra che qualcosa sia andato storto. Riprova tra un po'. Se l'errore persiste, contatta il nostro team di supporto.",
|
||||
"networkHostLookUpErr": "Impossibile connettersi a Ente, controlla le impostazioni di rete e contatta l'assistenza se l'errore persiste.",
|
||||
"networkConnectionRefusedErr": "Impossibile connettersi a Ente, riprova tra un po' di tempo. Se l'errore persiste, contatta l'assistenza.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Sembra che qualcosa sia andato storto. Riprova tra un po'. Se l'errore persiste, contatta il nostro team di supporto.",
|
||||
"about": "Informazioni",
|
||||
"weAreOpenSource": "Siamo open source!",
|
||||
|
||||
@@ -263,12 +263,15 @@
|
||||
"exportLogs": "ログのエクスポート",
|
||||
"enterYourRecoveryKey": "回復キーを入力",
|
||||
"tempErrorContactSupportIfPersists": "問題が発生したようです。しばらくしてから再試行してください。エラーが解決しない場合は、サポートチームにお問い合わせください。",
|
||||
"networkHostLookUpErr": "Enteに接続できませんでした。ネットワーク設定を確認し、エラーが解決しない場合はサポートにお問い合わせください。",
|
||||
"networkConnectionRefusedErr": "Enteに接続できませんでした。しばらくしてから再試行してください。エラーが解決しない場合は、サポートにお問い合わせください。",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "問題が発生したようです。しばらくしてから再試行してください。エラーが解決しない場合は、サポートチームにお問い合わせください。",
|
||||
"about": "情報",
|
||||
"weAreOpenSource": "我々はオープンソースです!",
|
||||
"privacy": "プライバシー",
|
||||
"terms": "利用規約",
|
||||
"checkForUpdates": "アップデートを確認",
|
||||
"checkStatus": "ステータスの確認",
|
||||
"downloadUpdate": "ダウンロード",
|
||||
"criticalUpdateAvailable": "重要な更新が利用可能です",
|
||||
"updateAvailable": "更新が利用可能です",
|
||||
@@ -417,6 +420,9 @@
|
||||
"waitingForBrowserRequest": "ブラウザのリクエストを待っています...",
|
||||
"waitingForVerification": "認証を待っています...",
|
||||
"passkey": "パスキー",
|
||||
"passKeyPendingVerification": "認証はまだ保留中です",
|
||||
"loginSessionExpired": "セッションの有効期限が切れました",
|
||||
"loginSessionExpiredDetails": "セッションの有効期限が切れました。再度ログインしてください。",
|
||||
"developerSettingsWarning": "開発者向け設定を変更してもよろしいですか?",
|
||||
"developerSettings": "開発者向け設定",
|
||||
"serverEndpoint": "サーバーエンドポイント",
|
||||
|
||||
@@ -263,12 +263,15 @@
|
||||
"exportLogs": "Logs exporteren",
|
||||
"enterYourRecoveryKey": "Voer je herstelsleutel in",
|
||||
"tempErrorContactSupportIfPersists": "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam.",
|
||||
"networkHostLookUpErr": "Kan geen verbinding maken met Ente, controleer uw netwerkinstellingen en neem contact op met ondersteuning als de fout zich blijft voordoen.",
|
||||
"networkConnectionRefusedErr": "Kan geen verbinding maken met Ente, probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met support.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Het lijkt erop dat er iets fout is gegaan. Probeer het later opnieuw. Als de fout zich blijft voordoen, neem dan contact op met ons supportteam.",
|
||||
"about": "Over",
|
||||
"weAreOpenSource": "We zijn open source!",
|
||||
"privacy": "Privacy",
|
||||
"terms": "Voorwaarden",
|
||||
"checkForUpdates": "Controleer op updates",
|
||||
"checkStatus": "Status controleren",
|
||||
"downloadUpdate": "Downloaden",
|
||||
"criticalUpdateAvailable": "Belangrijke update beschikbaar",
|
||||
"updateAvailable": "Update beschikbaar",
|
||||
@@ -417,6 +420,9 @@
|
||||
"waitingForBrowserRequest": "Wachten op browserverzoek...",
|
||||
"waitingForVerification": "Wachten op verificatie...",
|
||||
"passkey": "Passkey",
|
||||
"passKeyPendingVerification": "Verificatie is nog in behandeling",
|
||||
"loginSessionExpired": "Sessie verlopen",
|
||||
"loginSessionExpiredDetails": "Jouw sessie is verlopen. Log opnieuw in.",
|
||||
"developerSettingsWarning": "Weet u zeker dat u de ontwikkelaarsinstellingen wilt wijzigen?",
|
||||
"developerSettings": "Ontwikkelaarsinstellingen",
|
||||
"serverEndpoint": "Server eindpunt",
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"codeIssuerHint": "Wydawca",
|
||||
"codeSecretKeyHint": "Tajny klucz",
|
||||
"codeAccountHint": "Konto (ty@domena.com)",
|
||||
"codeTagHint": "Oznacz",
|
||||
"accountKeyType": "Rodzaj klucza",
|
||||
"sessionExpired": "Sesja wygasła",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -77,13 +79,19 @@
|
||||
"data": "Dane",
|
||||
"importCodes": "Importuj kody",
|
||||
"importTypePlainText": "Zwykły tekst",
|
||||
"importTypeEnteEncrypted": "Zaszyfrowany eksport Ente",
|
||||
"passwordForDecryptingExport": "Hasło do odszyfrowania eksportu",
|
||||
"passwordEmptyError": "Pole hasło nie może być puste",
|
||||
"importFromApp": "Importuj kody z {appName}",
|
||||
"importGoogleAuthGuide": "Wyeksportuj twoje konta z Google Authenticator do kodu QR używając opcji \"Przenieś konta\". Potem używając innego urządzenia, zeskanuj kod QR.",
|
||||
"importSelectJsonFile": "Wybierz plik JSON",
|
||||
"importSelectAppExport": "Wybierz plik eksportu {appName}",
|
||||
"importEnteEncGuide": "Wybierz zaszyfrowany plik JSON wyeksportowany z Ente",
|
||||
"importRaivoGuide": "Użyj opcji \"Eksportuj OTP do archiwum ZIP\" w Ustawieniach Raivo.\n\nWyodrębnij plik zip i zaimportuj plik JSON.",
|
||||
"importBitwardenGuide": "Użyj opcji \"Eksportuj sejf\" w Narzędziach Bitwarden i zaimportuj niezaszyfrowany plik JSON.",
|
||||
"importAegisGuide": "Użyj opcji \"Eksportuj sejf\" w ustawieniach Aegis.\n\nJeśli twój sejf jest zaszyfrowany, musisz wprowadzić hasło sejfu, aby odszyfrować sejf.",
|
||||
"import2FasGuide": "Użyj opcji \"Ustawienia->Kopia Zapasowa-Eksport\" w 2FAS.\n\nJeśli twoja kopia zapasowa jest zaszyfrowana, musisz wprowadzić hasło, aby odszyfrować kopię zapasową",
|
||||
"importLastpassGuide": "Użyj opcji \"Przenieś konta\" w Ustawieniach Lastpass Authenticator i naciśnij \"Eksportuj konta do pliku\". Zaimportuj pobrany plik JSON.",
|
||||
"exportCodes": "Eksportuj kody",
|
||||
"importLabel": "Importuj",
|
||||
"importInstruction": "Wybierz plik, który zawiera listę twoich kodów w następującym formacie",
|
||||
@@ -96,6 +104,7 @@
|
||||
"authToChangeYourEmail": "Proszę uwierzytelnić, aby zmienić swój adres e-mail",
|
||||
"authToChangeYourPassword": "Proszę uwierzytelnić, aby zmienić hasło",
|
||||
"authToViewSecrets": "Proszę uwierzytelnić, aby wyświetlić swoje sekrety",
|
||||
"authToInitiateSignIn": "Proszę uwierzytelnić się, aby zainicjować logowanie do kopii zapasowej.",
|
||||
"ok": "Ok",
|
||||
"cancel": "Anuluj",
|
||||
"yes": "Tak",
|
||||
@@ -107,18 +116,22 @@
|
||||
"copied": "Skopiowano",
|
||||
"pleaseTryAgain": "Proszę spróbować ponownie",
|
||||
"existingUser": "Istniejący użytkownik",
|
||||
"newUser": "Nowy/a do Ente",
|
||||
"delete": "Usuń",
|
||||
"enterYourPasswordHint": "Wprowadź swoje hasło",
|
||||
"forgotPassword": "Nie pamiętam hasła",
|
||||
"oops": "Ups",
|
||||
"suggestFeatures": "Zaproponuj funkcje",
|
||||
"faq": "Najczęściej zadawane pytania (FAQ)",
|
||||
"faq_q_1": "Jak bezpieczny jest Auth?",
|
||||
"faq_a_1": "Wszystkie kody, których tworzysz kopię zapasową za pomocą Ente są przechowywane zaszyfrowane end-to-end. Oznacza to, że tylko Ty możesz uzyskać dostęp do swoich kodów. Nasze aplikacje są otwarto-źródłowe, a nasza kryptografia została poddana zewnętrznemu audytowi.",
|
||||
"faq_q_2": "Czy mogę uzyskać dostęp do moich kodów na komputerze?",
|
||||
"faq_a_2": "Możesz uzyskać dostęp do swoich kodów na stronie auth.ente.io.",
|
||||
"faq_q_3": "Jak mogę usunąć kody?",
|
||||
"faq_a_3": "Możesz usunąć kod, przesuwając go w lewo.",
|
||||
"faq_q_4": "Jak mogę wesprzeć ten projekt?",
|
||||
"faq_a_4": "Możesz wspierać rozwój tego projektu, subskrybując do naszej aplikacji Zdjęcia na ente.io.",
|
||||
"faq_q_5": "Jak mogę włączyć blokadę FaceID w Ente Auth",
|
||||
"faq_a_5": "Możesz włączyć blokadę FaceID w Ustawienia → Bezpieczeństwo→ Ekran blokady.",
|
||||
"somethingWentWrongMessage": "Coś poszło nie tak. Proszę, spróbuj ponownie",
|
||||
"leaveFamily": "Opuść rodzinę",
|
||||
@@ -132,6 +145,8 @@
|
||||
"enterCodeHint": "Wprowadź sześciocyfrowy kod z twojej aplikacji uwierzytelniającej",
|
||||
"lostDeviceTitle": "Zagubiono urządzenie?",
|
||||
"twoFactorAuthTitle": "Uwierzytelnianie dwuetapowe",
|
||||
"passkeyAuthTitle": "Weryfikacja kluczem dostępu",
|
||||
"verifyPasskey": "Zweryfikuj klucz dostępu",
|
||||
"recoverAccount": "Odzyskaj konto",
|
||||
"enterRecoveryKeyHint": "Wprowadź swój klucz odzyskiwania",
|
||||
"recover": "Odzyskaj",
|
||||
@@ -143,6 +158,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"invalidQRCode": "Nieprawidłowy kod QR",
|
||||
"noRecoveryKeyTitle": "Brak klucza odzyskiwania?",
|
||||
"enterEmailHint": "Wprowadź adres e-mail",
|
||||
"invalidEmailTitle": "Nieprawidłowy adres e-mail",
|
||||
@@ -187,6 +203,8 @@
|
||||
"saveKey": "Zapisz klucz",
|
||||
"save": "Zapisz",
|
||||
"send": "Wyślij",
|
||||
"saveOrSendDescription": "Czy chcesz zapisać to do pamięci masowej (domyślnie folder Pobrane) czy wysłać to do innych aplikacji?",
|
||||
"saveOnlyDescription": "Czy chcesz zapisać to do pamięci masowej (domyślnie folder Pobrane)?",
|
||||
"back": "Wstecz",
|
||||
"createAccount": "Utwórz konto",
|
||||
"passwordStrength": "Siła hasła: {passwordStrengthValue}",
|
||||
@@ -245,12 +263,15 @@
|
||||
"exportLogs": "Eksportuj logi",
|
||||
"enterYourRecoveryKey": "Wprowadź swój klucz odzyskiwania",
|
||||
"tempErrorContactSupportIfPersists": "Wygląda na to, że coś poszło nie tak. Spróbuj ponownie po pewnym czasie. Jeśli błąd będzie się powtarzał, skontaktuj się z naszym zespołem pomocy technicznej.",
|
||||
"networkHostLookUpErr": "Nie można połączyć się z Ente, sprawdź ustawienia sieci i skontaktuj się z pomocą techniczną, jeśli błąd będzie się powtarzał.",
|
||||
"networkConnectionRefusedErr": "Nie można połączyć się z Ente, spróbuj ponownie po pewnym czasie. Jeśli błąd będzie się powtarzał, skontaktuj się z pomocą techniczną.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Wygląda na to, że coś poszło nie tak. Spróbuj ponownie po pewnym czasie. Jeśli błąd będzie się powtarzał, skontaktuj się z naszym zespołem pomocy technicznej.",
|
||||
"about": "O nas",
|
||||
"weAreOpenSource": "Posiadamy otwarte źródło!",
|
||||
"privacy": "Prywatność",
|
||||
"terms": "Warunki",
|
||||
"checkForUpdates": "Sprawdź czy są dostępne nowe aktualizacje",
|
||||
"checkStatus": "Sprawdź stan",
|
||||
"downloadUpdate": "Pobierz",
|
||||
"criticalUpdateAvailable": "Dostępna jest krytyczna aktualizacja",
|
||||
"updateAvailable": "Dostępna jest aktualizacja",
|
||||
@@ -326,6 +347,7 @@
|
||||
"offlineModeWarning": "Wybrałeś kontynuację bez kopii zapasowych. Proszę wykonywać ręczne kopie zapasowe, aby upewnić się, że Twoje kody są bezpieczne.",
|
||||
"showLargeIcons": "Pokaż duże ikony",
|
||||
"shouldHideCode": "Ukryj kody",
|
||||
"doubleTapToViewHiddenCode": "Możesz kliknąć dwukrotnie na wpis, aby wyświetlić kod",
|
||||
"focusOnSearchBar": "Uaktywnij wyszukiwanie przy uruchamianiu aplikacji",
|
||||
"confirmUpdatingkey": "Czy na pewno chcesz zaktualizować tajny klucz?",
|
||||
"minimizeAppOnCopy": "Minimalizuj aplikację przy kopiowaniu",
|
||||
@@ -333,10 +355,19 @@
|
||||
"deleteCodeAuthMessage": "Uwierzytelnij, aby usunąć kod",
|
||||
"showQRAuthMessage": "Uwierzytelnij, aby pokazać kod QR",
|
||||
"confirmAccountDeleteTitle": "Potwierdź usunięcie konta",
|
||||
"confirmAccountDeleteMessage": "To konto jest połączone z innymi aplikacjami Ente, jeśli ich używasz.\n\nTwoje przesłane dane, we wszystkich aplikacjach Ente, zostaną zaplanowane do usunięcia, a Twoje konto zostanie trwale usunięte.",
|
||||
"androidBiometricHint": "Potwierdź swoją tożsamość",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Nie rozpoznano. Spróbuj ponownie.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Sukces",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "Anuluj",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
@@ -345,13 +376,71 @@
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricRequiredTitle": "Wymagana biometria",
|
||||
"@androidBiometricRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsRequiredTitle": "Wymagane dane logowania urządzenia",
|
||||
"@androidDeviceCredentialsRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsSetupDescription": "Wymagane dane logowania urządzenia",
|
||||
"@androidDeviceCredentialsSetupDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"goToSettings": "Przejdź do Ustawień",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"androidGoToSettingsDescription": "Uwierzytelnianie biometryczne nie jest skonfigurowane na tym urządzeniu. Przejdź do 'Ustawienia > Bezpieczeństwo', aby dodać uwierzytelnianie biometryczne.",
|
||||
"@androidGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"iOSLockOut": "Uwierzytelnianie biometryczne jest wyłączone. Proszę zablokować i odblokować ekran, aby je włączyć.",
|
||||
"@iOSLockOut": {
|
||||
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSGoToSettingsDescription": "Uwierzytelnianie biometryczne nie jest skonfigurowane na Twoim urządzeniu. Proszę włączyć Touch ID lub Face ID na swoim telefonie.",
|
||||
"@iOSGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSOkButton": "OK",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"noInternetConnection": "Brak połączenia z Internetem",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Proszę sprawdzić połączenie internetowe i spróbować ponownie.",
|
||||
"signOutFromOtherDevices": "Wyloguj z pozostałych urządzeń",
|
||||
"signOutOtherBody": "Jeśli uważasz, że ktoś może znać Twoje hasło, możesz wymusić wylogowanie na wszystkich innych urządzeniach korzystających z Twojego konta.",
|
||||
"signOutOtherDevices": "Wyloguj z pozostałych urządzeń",
|
||||
"doNotSignOut": "Nie wylogowuj mnie",
|
||||
"hearUsWhereTitle": "Jak usłyszałeś o Ente? (opcjonalnie)",
|
||||
"hearUsExplanation": "Nie śledzimy instalacji aplikacji. Pomogłyby nam, gdybyś powiedział/a nam, gdzie nas znalazłeś/aś!",
|
||||
"recoveryKeySaved": "Klucz odzyskiwania zapisany w folderze Pobrane!",
|
||||
"waitingForBrowserRequest": "Oczekiwanie na żądanie przeglądarki...",
|
||||
"waitingForVerification": "Oczekiwanie na weryfikację...",
|
||||
"developerSettings": "Ustawienia deweloperskie"
|
||||
"passkey": "Klucz dostępu",
|
||||
"passKeyPendingVerification": "Weryfikacja jest nadal w toku",
|
||||
"loginSessionExpired": "Sesja wygasła",
|
||||
"loginSessionExpiredDetails": "Twoja sesja wygasła. Zaloguj się ponownie.",
|
||||
"developerSettingsWarning": "Czy na pewno chcesz zmodyfikować ustawienia programisty?",
|
||||
"developerSettings": "Ustawienia deweloperskie",
|
||||
"serverEndpoint": "Punkt końcowy serwera",
|
||||
"invalidEndpoint": "Punkt końcowy jest nieprawidłowy",
|
||||
"invalidEndpointMessage": "Niestety, wprowadzony punkt końcowy jest nieprawidłowy. Wprowadź prawidłowy punkt końcowy i spróbuj ponownie.",
|
||||
"endpointUpdatedMessage": "Punkt końcowy zaktualizowany pomyślnie",
|
||||
"customEndpoint": "Połączono z {endpoint}",
|
||||
"pinText": "Przypnij",
|
||||
"unpinText": "Odepnij",
|
||||
"pinnedCodeMessage": "Przypięto {code}",
|
||||
"unpinnedCodeMessage": "Odpięto {code}",
|
||||
"tags": "Etykiety",
|
||||
"createNewTag": "Utwórz Nową Etykietę",
|
||||
"tag": "Etykieta",
|
||||
"create": "Utwórz",
|
||||
"editTag": "Edytuj Etykietę",
|
||||
"deleteTagTitle": "Usunąć etykietę?",
|
||||
"deleteTagMessage": "Czy na pewno chcesz usunąć tę etykietę? Ta akcja jest nieodwracalna.",
|
||||
"somethingWentWrongParsingCode": "Nie udało się przetworzyć kodów {x}.",
|
||||
"updateNotAvailable": "Aktualizacja jest niedostępna"
|
||||
}
|
||||
@@ -146,7 +146,7 @@
|
||||
"lostDeviceTitle": "Perdeu um dispositivo?",
|
||||
"twoFactorAuthTitle": "Autenticação de dois fatores",
|
||||
"passkeyAuthTitle": "Autenticação via Chave de acesso",
|
||||
"verifyPasskey": "Verificar senha-mestra",
|
||||
"verifyPasskey": "Verificar chave de acesso",
|
||||
"recoverAccount": "Recuperar conta",
|
||||
"enterRecoveryKeyHint": "Digite a chave de recuperação",
|
||||
"recover": "Recuperar",
|
||||
@@ -263,6 +263,8 @@
|
||||
"exportLogs": "Exportar logs",
|
||||
"enterYourRecoveryKey": "Digite a chave de recuperação",
|
||||
"tempErrorContactSupportIfPersists": "Parece que algo deu errado. Por favor, tente novamente mais tarde. Se o erro persistir, entre em contato com nossa equipe de suporte.",
|
||||
"networkHostLookUpErr": "Não foi possível conectar-se ao Ente, verifique suas configurações de rede e entre em contato com o suporte se o erro persistir.",
|
||||
"networkConnectionRefusedErr": "Não foi possível conectar ao Ente, tente novamente após algum tempo. Se o erro persistir, entre em contato com o suporte.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Parece que algo deu errado. Por favor, tente novamente mais tarde. Se o erro persistir, entre em contato com nossa equipe de suporte.",
|
||||
"about": "Sobre",
|
||||
"weAreOpenSource": "Nós somos de código aberto!",
|
||||
@@ -417,7 +419,7 @@
|
||||
"recoveryKeySaved": "Chave de recuperação salva na pasta Downloads!",
|
||||
"waitingForBrowserRequest": "Aguardando solicitação do navegador...",
|
||||
"waitingForVerification": "Esperando por verificação...",
|
||||
"passkey": "Senha-mestra",
|
||||
"passkey": "Chave de acesso",
|
||||
"passKeyPendingVerification": "A verificação ainda está pendente",
|
||||
"loginSessionExpired": "Sessão expirada",
|
||||
"loginSessionExpiredDetails": "Sua sessão expirou. Por favor, entre novamente.",
|
||||
@@ -440,5 +442,5 @@
|
||||
"deleteTagTitle": "Apagar etiqueta?",
|
||||
"deleteTagMessage": "Tem certeza de que deseja excluir esta etiqueta? Essa ação é irreversível.",
|
||||
"somethingWentWrongParsingCode": "Não foi possível analisar os códigos {x}.",
|
||||
"updateNotAvailable": "Atualização não está disponível"
|
||||
"updateNotAvailable": "Atualização indisponível"
|
||||
}
|
||||
232
auth/lib/l10n/arb/app_ro.arb
Normal file
@@ -0,0 +1,232 @@
|
||||
{
|
||||
"account": "Cont",
|
||||
"unlock": "Deblochează",
|
||||
"recoveryKey": "Cheie de recuperare",
|
||||
"onBoardingBody": "Salvează în siguranță codurile 2FA",
|
||||
"onBoardingGetStarted": "Începe",
|
||||
"setupFirstAccount": "Configurează primul cont",
|
||||
"importScanQrCode": "Scanează un cod QR",
|
||||
"qrCode": "Cod QR",
|
||||
"importEnterSetupKey": "Introdu o cheie de configurare",
|
||||
"importAccountPageTitle": "Introdu detaliile contului",
|
||||
"secretCanNotBeEmpty": "Secretul nu poate fi gol",
|
||||
"incorrectDetails": "Detalii incorecte",
|
||||
"pleaseVerifyDetails": "Te rog verifică detaliile și încearcă din nou",
|
||||
"codeIssuerHint": "Emitent",
|
||||
"codeSecretKeyHint": "Cheie Secretă",
|
||||
"codeAccountHint": "Cont (tu@domeniu.com)",
|
||||
"codeTagHint": "Etichetă",
|
||||
"accountKeyType": "Tipul de cheie",
|
||||
"sessionExpired": "Sesiune expirată",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "Te rugăm să te autentifici din nou",
|
||||
"loggingOut": "Deconectare...",
|
||||
"timeBasedKeyType": "Bazat pe timp (TOTP)",
|
||||
"counterBasedKeyType": "Bazat pe contor (HOTP)",
|
||||
"saveAction": "Salvare",
|
||||
"nextTotpTitle": "următor",
|
||||
"deleteCodeTitle": "Șterge codul?",
|
||||
"deleteCodeMessage": "Ești sigur că vrei să ștergi acest cod? Acțiunea este ireversibilă.",
|
||||
"viewLogsAction": "Afișare jurnale",
|
||||
"preparingLogsTitle": "Se pregătesc jurnalele...",
|
||||
"emailLogsTitle": "Jurnale e-mail",
|
||||
"emailLogsMessage": "Te rugăm să trimiți jurnalele la {email}",
|
||||
"@emailLogsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"copyEmailAction": "Copiază e-mailul",
|
||||
"exportLogsAction": "Exportează log-urile",
|
||||
"reportABug": "Raportează o eroare",
|
||||
"crashAndErrorReporting": "Închidere accidentală şi raportare erori",
|
||||
"reportBug": "Raportare bug",
|
||||
"emailUsMessage": "Te rugăm să ne trimiți un e-mail la {email}",
|
||||
"@emailUsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contactSupport": "Contactează suportul",
|
||||
"rateUsOnStore": "Evaluează-ne pe {storeName}",
|
||||
"blog": "Blog",
|
||||
"verifyPassword": "Verifică parola",
|
||||
"pleaseWait": "Te rog așteaptă...",
|
||||
"recreatePassword": "Recreează parola",
|
||||
"incorrectPasswordTitle": "Parolă incorectă",
|
||||
"welcomeBack": "Bine ai revenit!",
|
||||
"supportDevs": "Abonează-te la <bold-green>ente</bold-green> pentru a ne susține",
|
||||
"supportDiscount": "Folosește codul \"AUTH\" pentru a obține o reducere de 10% în primul an",
|
||||
"changeEmail": "Schimbă e-mailul",
|
||||
"changePassword": "Schimbă parola",
|
||||
"data": "Date",
|
||||
"importCodes": "Importă coduri",
|
||||
"importTypePlainText": "Text simplu",
|
||||
"passwordForDecryptingExport": "Parola pentru a decripta exportul",
|
||||
"passwordEmptyError": "Parola nu poate fi goală",
|
||||
"importFromApp": "Importă coduri din {appName}",
|
||||
"importSelectJsonFile": "Selectează fișierul JSON",
|
||||
"importSelectAppExport": "Selectează fișierul de export din {appName}",
|
||||
"importEnteEncGuide": "Selectează fișierul criptat JSON exportat din Bențe",
|
||||
"exportCodes": "Exportă coduri",
|
||||
"importLabel": "Importă",
|
||||
"selectFile": "Selectează fișier",
|
||||
"emailVerificationToggle": "Verificarea adresei de e-mail",
|
||||
"authToChangeEmailVerificationSetting": "Te rugăm să te autentifici pentru a schimba verificarea prin e-mail",
|
||||
"authToChangeYourEmail": "Te rugăm să te autentifici pentru a-ți schimba adresa de e-mail",
|
||||
"ok": "Ok",
|
||||
"cancel": "Anulare",
|
||||
"yes": "Da",
|
||||
"no": "Nu",
|
||||
"email": "E-mail",
|
||||
"support": "Asistență",
|
||||
"general": "General",
|
||||
"settings": "Setări",
|
||||
"copied": "S-a copiat",
|
||||
"pleaseTryAgain": "Te rugăm să încerci din nou",
|
||||
"existingUser": "Utilizator existent",
|
||||
"newUser": "Nou în Ente",
|
||||
"delete": "Ștergere",
|
||||
"enterYourPasswordHint": "Introdu parola",
|
||||
"forgotPassword": "Am uitat parola",
|
||||
"oops": "Ups",
|
||||
"suggestFeatures": "Sugerează funcționalități",
|
||||
"faq": "Întrebări frecvente",
|
||||
"faq_q_1": "Cât de sigur este Auth?",
|
||||
"faq_q_2": "Pot accesa codurile de pe desktop?",
|
||||
"faq_q_3": "Cum pot șterge codurile?",
|
||||
"faq_q_4": "Cum pot susţine acest proiect?",
|
||||
"faq_a_4": "Poți susține dezvoltarea acestui proiect prin cumpărarea unui abonament la aplicația noastră de fotografii @ ente.io.",
|
||||
"faq_q_5": "Cum pot activa blocarea cu FaceID în Auth",
|
||||
"faq_a_5": "Poți activa blocarea FaceID din Setări → Securitate → Ecran de blocare.",
|
||||
"somethingWentWrongMessage": "Ceva n-a mers bine, te rog încearcă din nou",
|
||||
"leaveFamily": "Părăsește familia",
|
||||
"verifyEmail": "Verifică e-mail",
|
||||
"twoFactorAuthTitle": "Autentificare cu doi factori",
|
||||
"recoverAccount": "Recuperare cont",
|
||||
"recover": "Recuperează",
|
||||
"invalidQRCode": "Codul QR nu este valid",
|
||||
"enterEmailHint": "Introdu adresa ta de e-mail",
|
||||
"invalidEmailTitle": "Adresa e-mail nu este validă",
|
||||
"invalidEmailMessage": "Te rugăm să introduci o adresă de e-mail validă.",
|
||||
"deleteAccount": "Ștergere cont",
|
||||
"yesSendFeedbackAction": "Da, trimite feedback",
|
||||
"noDeleteAccountAction": "Nu, șterge contul",
|
||||
"initiateAccountDeleteTitle": "Te rugăm să te autentifici pentru a iniția ștergerea contului",
|
||||
"sendEmail": "Trimite e-mail",
|
||||
"confirmPassword": "Confirmă parola",
|
||||
"close": "Închide",
|
||||
"selectLanguage": "Selectare limbă",
|
||||
"language": "Limbă",
|
||||
"social": "Social",
|
||||
"security": "Securitate",
|
||||
"lockscreen": "Ecran de blocare",
|
||||
"scanAQrCode": "Scanează un cod QR",
|
||||
"copiedToClipboard": "Copiat în clipboard",
|
||||
"copiedNextToClipboard": "Codul următor a fost copiat în clipboard",
|
||||
"error": "Eroare",
|
||||
"recoveryKeyOnForgotPassword": "Dacă îți uiți parola, singura modalitate prin care poți recupera datele este cu această cheie.",
|
||||
"saveKey": "Salvare cheie",
|
||||
"save": "Salvare",
|
||||
"send": "Trimitere",
|
||||
"back": "Înapoi",
|
||||
"password": "Parolă",
|
||||
"termsOfServicesTitle": "Termeni",
|
||||
"setPasswordTitle": "Setează parola",
|
||||
"changePasswordTitle": "Schimbă parola",
|
||||
"resetPasswordTitle": "Resetează parola",
|
||||
"passwordWarning": "Nu stocăm această parolă, deci dacă o uiți, <underline>nu îți putem decripta datele</underline>",
|
||||
"enterPasswordToEncrypt": "Introdu o parolă pe care o putem folosi pentru a-ți cripta datele",
|
||||
"passwordChangedSuccessfully": "Parola a fost modificată cu succes",
|
||||
"recreatePasswordTitle": "Recreează parola",
|
||||
"invalidKey": "Cheie invalidă",
|
||||
"tryAgain": "Încearcă din nou",
|
||||
"viewRecoveryKey": "Vezi cheia de recuperare",
|
||||
"pleaseSendTheLogsTo": "Te rugăm să trimiți jurnalele la {toEmail}",
|
||||
"copyEmailAddress": "Copiază adresa de e-mail",
|
||||
"about": "Despre",
|
||||
"weAreOpenSource": "Suntem open source!",
|
||||
"privacy": "Confidențialitate",
|
||||
"terms": "Termeni",
|
||||
"checkForUpdates": "Verifică actualizări",
|
||||
"checkStatus": "Verifică status",
|
||||
"downloadUpdate": "Descărcare",
|
||||
"criticalUpdateAvailable": "Actualizare critică disponibilă",
|
||||
"updateAvailable": "Actualizare disponibilă",
|
||||
"update": "Actualizare",
|
||||
"checking": "Se verifică...",
|
||||
"youAreOnTheLatestVersion": "Utilizezi cea mai recentă versiune",
|
||||
"warning": "Atenție",
|
||||
"iUnderStand": "Înţeleg",
|
||||
"@iUnderStand": {
|
||||
"description": "Text for the button to confirm the user understands the warning"
|
||||
},
|
||||
"importSuccessTitle": "Ura!",
|
||||
"sorry": "Ne pare rău",
|
||||
"pendingSyncs": "Atenție",
|
||||
"tapToEnterCode": "Apasă pentru a introduce codul",
|
||||
"resendEmail": "Retrimite e-mail",
|
||||
"weHaveSendEmailTo": "Am trimis un e-mail la <green>{email}</green>",
|
||||
"@weHaveSendEmailTo": {
|
||||
"description": "Text to indicate that we have sent a mail to the user",
|
||||
"placeholders": {
|
||||
"email": {
|
||||
"description": "The email address of the user",
|
||||
"type": "String",
|
||||
"example": "example@ente.io"
|
||||
}
|
||||
}
|
||||
},
|
||||
"activeSessions": "Sesiuni active",
|
||||
"somethingWentWrongPleaseTryAgain": "Ceva n-a mers bine, te rog încearcă din nou",
|
||||
"thisDevice": "Acest dispozitiv",
|
||||
"toResetVerifyEmail": "Pentru a reseta parola, te rugăm să confirmi mai întâi adresa de e-mail.",
|
||||
"thisEmailIsAlreadyInUse": "Această adresă de e-mail este deja folosită",
|
||||
"emailChangedTo": "E-mail modificat în {newEmail}",
|
||||
"enterPassword": "Introdu parola",
|
||||
"passwordToEncryptExport": "Parolă pentru a cripta exportul",
|
||||
"useOffline": "Utilizează fără backup-uri",
|
||||
"offlineModeWarning": "Ai ales să continui fără backup-uri. Te rog salvează-ți backup-urile manual ca să fii sigur că ai codurile în siguranță.",
|
||||
"showLargeIcons": "Afișează iconițele mari",
|
||||
"shouldHideCode": "Ascunde codurile",
|
||||
"androidBiometricHint": "Verifică identitatea",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Neidentificat. Încearcă din nou.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Succes",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "Anulare",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "Autentificare necesară",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"goToSettings": "Mergi la setări",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"iOSOkButton": "Ok",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"noInternetConnection": "Nu există conexiune la internet",
|
||||
"signOutFromOtherDevices": "Deconectare de pe alte dispozitive",
|
||||
"signOutOtherDevices": "Deconectează alte dispozitive",
|
||||
"doNotSignOut": "Nu te deconecta",
|
||||
"loginSessionExpired": "Sesiune expirată",
|
||||
"updateNotAvailable": "Actualizare indisponibilă"
|
||||
}
|
||||
@@ -20,6 +20,8 @@
|
||||
"codeIssuerHint": "ኣዋጂ",
|
||||
"codeSecretKeyHint": "ምስጢራዊ መፍትሕ",
|
||||
"codeAccountHint": "ሕሳብ (you@domain.com)",
|
||||
"codeTagHint": "ልጣፍ",
|
||||
"accountKeyType": "ዓይነት ቁልፊ",
|
||||
"sessionExpired": "ክፍለ ግዜኡ ኣኺሉ።",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -111,12 +113,14 @@
|
||||
"copied": "Copied",
|
||||
"pleaseTryAgain": "Please try again",
|
||||
"existingUser": "Existing User",
|
||||
"newUser": "ሓድሽ ናብ Ente",
|
||||
"delete": "Delete",
|
||||
"enterYourPasswordHint": "Enter your password",
|
||||
"forgotPassword": "Forgot password",
|
||||
"oops": "ዉዉኡ",
|
||||
"suggestFeatures": "Suggest features",
|
||||
"faq": "FAQ",
|
||||
"faq_q_1": "Auth ክሳብ ክንደይ ውሑስ እዩ፧",
|
||||
"faq_q_2": "Can I access my codes on desktop?",
|
||||
"faq_a_2": "You can access your codes on the web @ auth.ente.io.",
|
||||
"faq_q_3": "How can I delete codes?",
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
"privacy": "Gizlilik",
|
||||
"terms": "Şartlar",
|
||||
"checkForUpdates": "Güncellemeleri denetleyin",
|
||||
"checkStatus": "Durumu kontrol et",
|
||||
"downloadUpdate": "İndir",
|
||||
"criticalUpdateAvailable": "Kritik güncelleme mevcut",
|
||||
"updateAvailable": "Güncelleme mevcut",
|
||||
@@ -417,6 +418,9 @@
|
||||
"waitingForBrowserRequest": "Tarayıcı isteği bekleniyor...",
|
||||
"waitingForVerification": "Doğrulama bekleniyor...",
|
||||
"passkey": "Geçiş anahtarı",
|
||||
"passKeyPendingVerification": "Doğrulama hala bekliyor",
|
||||
"loginSessionExpired": "Oturum süresi doldu",
|
||||
"loginSessionExpiredDetails": "Oturum süreniz doldu. Tekrar giriş yapın.",
|
||||
"developerSettingsWarning": "Geliştirici ayarlarını değiştirmekten emin misiniz?",
|
||||
"developerSettings": "Geliştirici ayarları",
|
||||
"serverEndpoint": "Sunucu uç noktası",
|
||||
|
||||
@@ -263,6 +263,8 @@
|
||||
"exportLogs": "导出日志",
|
||||
"enterYourRecoveryKey": "输入您的恢复密钥",
|
||||
"tempErrorContactSupportIfPersists": "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。",
|
||||
"networkHostLookUpErr": "无法连接到 Ente,请检查您的网络设置,如果错误仍然存在,请联系支持。",
|
||||
"networkConnectionRefusedErr": "无法连接到 Ente,请稍后重试。如果错误仍然存在,请联系支持人员。",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "看起来出了点问题。 请稍后重试。 如果错误仍然存在,请联系我们的支持团队。",
|
||||
"about": "关于",
|
||||
"weAreOpenSource": "我们是开源的 !",
|
||||
|
||||
@@ -28,6 +28,7 @@ import 'package:ente_crypto_dart/ente_crypto_dart.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import "package:flutter/material.dart";
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
@@ -65,6 +66,9 @@ Future<void> initSystemTray() async {
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
if (Platform.isWindows) {
|
||||
await whiteListLetsEncryptRootCA();
|
||||
}
|
||||
|
||||
if (PlatformUtil.isDesktop()) {
|
||||
await windowManager.ensureInitialized();
|
||||
@@ -86,6 +90,19 @@ void main() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> whiteListLetsEncryptRootCA() async {
|
||||
try {
|
||||
// https://stackoverflow.com/a/71090239
|
||||
// https://github.com/ente-io/ente/issues/2178
|
||||
ByteData data =
|
||||
await PlatformAssetBundle().load('assets/ca/lets-encrypt-r3.pem');
|
||||
SecurityContext.defaultContext
|
||||
.setTrustedCertificatesBytes(data.buffer.asUint8List());
|
||||
} catch (e) {
|
||||
_logger.severe("Failed to whitelist Let's Encrypt Root CA", e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _runInForeground() async {
|
||||
final savedThemeMode = _themeMode(await AdaptiveTheme.getThemeMode());
|
||||
return await _runWithLogs(() async {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 3.0.17+317
|
||||
version: 3.0.18+318
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -132,6 +132,7 @@ flutter:
|
||||
- assets/custom-icons/icons/
|
||||
- assets/custom-icons/_data/
|
||||
- assets/svg/
|
||||
- assets/ca/
|
||||
|
||||
fonts:
|
||||
- family: Inter
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.20-alpine3.17 as builder
|
||||
FROM golang:1.20-alpine3.17 AS builder
|
||||
RUN apk add --no-cache gcc musl-dev git build-base pkgconfig libsodium-dev
|
||||
|
||||
ENV GOOS=linux
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.20-alpine3.17@sha256:9c2f89db6fda13c3c480749787f62fed5831699bb2c32881b8f327f1cf7bae42 as builder386
|
||||
FROM golang:1.20-alpine3.17@sha256:9c2f89db6fda13c3c480749787f62fed5831699bb2c32881b8f327f1cf7bae42 AS builder386
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y gcc
|
||||
RUN apt-get install -y git
|
||||
|
||||
@@ -17,8 +17,8 @@ on:
|
||||
#
|
||||
- cron: "45 2 * * 1-6"
|
||||
push:
|
||||
# Run when a tag matching the pattern "vd.d.d"" is pushed. Crucially for
|
||||
# us, this excludes the "-rc" tags.
|
||||
# Run when a tag matching the pattern "vd.d.d" is pushed. In particular,
|
||||
# this excludes the "-beta" tags.
|
||||
tags:
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v1.7.2 (Unreleased)
|
||||
## v1.7.2
|
||||
|
||||
- .
|
||||
- Significantly improve the speed of the metadata parsing step during imports
|
||||
of Google takeouts.
|
||||
- Add a option to set and use a custom endpoint.
|
||||
- Fix an issue preventing subscription purchases and renewals.
|
||||
- Clear cached password after changing it on a different device.
|
||||
- Reconcile exported files with disk on app start and resync.
|
||||
|
||||
## v1.7.1
|
||||
|
||||
|
||||
@@ -83,13 +83,17 @@ are similar to that in the web code.
|
||||
|
||||
Some extra ones specific to the code here are:
|
||||
|
||||
- [shx](https://github.com/shelljs/shx) for providing a portable way to use
|
||||
Unix commands in our `package.json` scripts. This allows us to use the same
|
||||
commands (like `ln`) across different platforms like Linux and Windows.
|
||||
|
||||
- [@tsconfig/recommended](https://github.com/tsconfig/bases) gives us a base
|
||||
tsconfig for the Node.js version that our current Electron version uses.
|
||||
|
||||
- [shx](https://github.com/shelljs/shx) provides us a portable way to use Unix
|
||||
commands in our `package.json` scripts. This allows us to use the same
|
||||
commands (like `ln`) across both POSIX platforms (Linux, macOS) and Windows.
|
||||
|
||||
- [cross-env](https://github.com/kentcdodds/cross-env) is similar to shx, but
|
||||
for allowing us to set environment variables in a way that also works on
|
||||
Windows.
|
||||
|
||||
## Functionality
|
||||
|
||||
### Format conversion
|
||||
@@ -108,23 +112,24 @@ resources (`build`) folder. This is used for thumbnail generation on Linux.
|
||||
On macOS, we use the `sips` CLI tool for conversion, but that is already
|
||||
available on the host machine, and is not bundled with our app.
|
||||
|
||||
### AI/ML
|
||||
### ML
|
||||
|
||||
[onnxruntime-node](https://github.com/Microsoft/onnxruntime) is used as the
|
||||
AI/ML runtime. It powers both natural language searches (using CLIP) and face
|
||||
[onnxruntime-node](https://github.com/Microsoft/onnxruntime) is used as the ML
|
||||
runtime. It powers both natural language searches (using CLIP) and face
|
||||
detection (using YOLO).
|
||||
|
||||
[jpeg-js](https://github.com/jpeg-js/jpeg-js#readme) is used for decoding JPEG
|
||||
data into raw RGB bytes before passing it to ONNX.
|
||||
|
||||
html-entities is used by the bundled clip-bpe-ts tokenizer for CLIP.
|
||||
|
||||
### Watch Folders
|
||||
|
||||
[chokidar](https://github.com/paulmillr/chokidar) is used as a file system
|
||||
watcher for the watch folders functionality.
|
||||
[clip-bpe-js](https://github.com/simonwarchol/clip-bpe-js) is used for tokening
|
||||
the user's search phrase before computing its CLIP (text) embedding.
|
||||
|
||||
### ZIP
|
||||
|
||||
[node-stream-zip](https://github.com/antelle/node-stream-zip) is used for
|
||||
reading of large ZIP files (e.g. during imports of Google Takeout ZIPs).
|
||||
|
||||
[lru-cache](https://github.com/isaacs/node-lru-cache) is used to cache file ZIP
|
||||
handles to avoid reopening them for every operation.
|
||||
|
||||
### Watch folders
|
||||
|
||||
[chokidar](https://github.com/paulmillr/chokidar) is used as a file system
|
||||
watcher for the watch folders functionality.
|
||||
|
||||
@@ -18,20 +18,19 @@ to keep a separate repository just for holding the releases.
|
||||
- Releases are done from
|
||||
[ente-io/photos-desktop](https://github.com/ente-io/photos-desktop).
|
||||
|
||||
## Workflow - Release candidates
|
||||
## Nightly builds
|
||||
|
||||
Nightly RC builds of `main` are published by a scheduled workflow automatically.
|
||||
If needed, these builds can also be manually updated, and the branch of the
|
||||
source repository to build (default "main") also specified:
|
||||
Nightly builds of `main` are published by a scheduled workflow automatically.
|
||||
Each such workflow run will update the artifacts attached to the same
|
||||
(pre-existing) pre-release.
|
||||
|
||||
If needed, this workflow can also be manually triggered:
|
||||
|
||||
```sh
|
||||
gh workflow run desktop-release.yml --source=<branch>
|
||||
```
|
||||
|
||||
Each such workflow run will update the artifacts attached to the same
|
||||
(pre-existing) pre-release.
|
||||
|
||||
## Workflow - Release
|
||||
## Release checklist
|
||||
|
||||
1. Update source repo to set version `1.x.x` in `package.json` and finalize the
|
||||
CHANGELOG.
|
||||
@@ -50,37 +49,38 @@ Each such workflow run will update the artifacts attached to the same
|
||||
```
|
||||
|
||||
This'll trigger the workflow and create a new pre-release. We can edit this to
|
||||
add the release notes, convert it to a release. Once it is marked as latest, the
|
||||
release goes live.
|
||||
add the release notes, and convert it to a release.
|
||||
|
||||
We are done at this point, and can now update the other pre-release that hosts
|
||||
Once it is marked as latest, the release goes live.
|
||||
|
||||
We are done at this point, and can now update the other pre-release that'll hold
|
||||
subsequent nightly builds.
|
||||
|
||||
1. Update `package.json` in the source repo to use version `1.x.x-rc`, and
|
||||
1. Update `package.json` in the source repo to use version `1.x.x-beta`, and
|
||||
merge these changes into `main`.
|
||||
|
||||
2. In the release repo, delete the existing _nightly_ pre-release, then:
|
||||
|
||||
```sh
|
||||
git tag 1.x.x-rc
|
||||
git push origin 1.x.x-rc
|
||||
git tag 1.x.x-beta
|
||||
git push origin 1.x.x-beta
|
||||
```
|
||||
|
||||
3. Start a new run of the workflow (`gh workflow run desktop-release.yml`).
|
||||
|
||||
Once the workflow finishes and the 1.x.x-rc pre-release is created, edit its
|
||||
description to "Nightly builds". Subsequent scheduled nightly builds will update
|
||||
this pre-release.
|
||||
Once the workflow finishes and the 1.x.x-beta pre-release is created, edit its
|
||||
description to "Nightly beta builds". Subsequent scheduled nightly workflows
|
||||
will keep updating this pre-release.
|
||||
|
||||
## Workflow - Extra pre-releases
|
||||
## Ad-hoc builds
|
||||
|
||||
To create extra one off pre-releases in addition to the nightly `1.x.x-rc` ones,
|
||||
To create extra one-off pre-releases in addition to the nightly `1.x.x-beta`s,
|
||||
|
||||
1. In your branch in the source repository, set the version in `package.json`
|
||||
to something different, say `1.x.x-my-test`.
|
||||
to something different, say `1.x.x-foo`.
|
||||
|
||||
2. Create a new pre-release in the release repo with title `1.x.x-test`. In the
|
||||
tag input enter `v1.x.x-test` and select the option to "create a new tag on
|
||||
2. Create a new pre-release in the release repo with title `1.x.x-foo`. In the
|
||||
tag input enter `v1.x.x-foo` and select the option to "Create a new tag on
|
||||
publish".
|
||||
|
||||
3. Trigger the workflow in the release repo:
|
||||
|
||||
@@ -38,6 +38,13 @@ export default ts.config(
|
||||
ignoreArrowShorthand: true,
|
||||
},
|
||||
],
|
||||
// Allow free standing ternary expressions.
|
||||
"@typescript-eslint/no-unused-expressions": [
|
||||
"error",
|
||||
{
|
||||
allowTernary: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ente",
|
||||
"version": "1.7.2-rc",
|
||||
"version": "1.7.2",
|
||||
"private": true,
|
||||
"description": "Desktop client for Ente Photos",
|
||||
"repository": "github:ente-io/photos-desktop",
|
||||
@@ -10,12 +10,12 @@
|
||||
"build": "yarn build-renderer && yarn build-main",
|
||||
"build-main": "tsc && electron-builder",
|
||||
"build-main:quick": "tsc && electron-builder --dir --config.compression=store --config.mac.identity=null",
|
||||
"build-renderer": "cd ../web && yarn install && yarn build:photos && cd ../desktop && shx rm -f out && shx ln -sf ../web/apps/photos/out out",
|
||||
"build-renderer": "cross-env-shell _ENTE_IS_DESKTOP=1 \"cd ../web && yarn install && yarn build:photos && cd ../desktop && shx rm -f out && shx ln -sf ../web/apps/photos/out out\"",
|
||||
"build:ci": "yarn build-renderer && tsc",
|
||||
"build:quick": "yarn build-renderer && yarn build-main:quick",
|
||||
"dev": "concurrently --kill-others --success first --names 'main,rndr' \"yarn dev-main\" \"yarn dev-renderer\"",
|
||||
"dev-main": "tsc && electron .",
|
||||
"dev-renderer": "cd ../web && yarn install && yarn dev:photos",
|
||||
"dev-renderer": "cross-env-shell _ENTE_IS_DESKTOP=1 \"cd ../web && yarn install && yarn dev:photos\"",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "yarn prettier --check --log-level warn . && yarn eslint && yarn tsc",
|
||||
"lint-fix": "yarn prettier --write --log-level warn . && yarn eslint && yarn tsc"
|
||||
@@ -27,33 +27,34 @@
|
||||
"any-shell-escape": "^0.1",
|
||||
"auto-launch": "^5.0",
|
||||
"chokidar": "^3.6",
|
||||
"clip-bpe-js": "^0.0.6",
|
||||
"compare-versions": "^6.1",
|
||||
"electron-log": "^5.1",
|
||||
"electron-store": "^8.2",
|
||||
"electron-updater": "^6.2",
|
||||
"ffmpeg-static": "^5.2",
|
||||
"html-entities": "^2.5",
|
||||
"jpeg-js": "^0.4",
|
||||
"lru-cache": "^10.2",
|
||||
"next-electron-server": "^1",
|
||||
"node-stream-zip": "^1.15",
|
||||
"onnxruntime-node": "^1.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.4.0",
|
||||
"@eslint/js": "^9",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/auto-launch": "^5.0",
|
||||
"@types/eslint__js": "^8.42.3",
|
||||
"@types/ffmpeg-static": "^3.0",
|
||||
"concurrently": "^8",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^30",
|
||||
"electron-builder": "25.0.0-alpha.8",
|
||||
"eslint": "^9.4.0",
|
||||
"eslint": "^9",
|
||||
"prettier": "^3",
|
||||
"prettier-plugin-organize-imports": "^3",
|
||||
"prettier-plugin-packagejson": "^2",
|
||||
"shx": "^0.3",
|
||||
"typescript": "^5",
|
||||
"typescript-eslint": "8.0.0-alpha.10"
|
||||
"typescript-eslint": "^8.0.0-alpha.39"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"productName": "ente"
|
||||
|
||||
@@ -295,9 +295,8 @@ const createMainWindow = () => {
|
||||
// On macOS, also hide the dock icon on macOS.
|
||||
if (process.platform == "darwin") app.dock.hide();
|
||||
} else {
|
||||
// Show our window otherwise.
|
||||
//
|
||||
// If we did not give it an explicit size, maximize it
|
||||
// Show our window otherwise, maximizing it if we're not asked to set it
|
||||
// to a specific size.
|
||||
bounds ? window.show() : window.maximize();
|
||||
}
|
||||
|
||||
@@ -538,7 +537,7 @@ const setupTrayItem = (mainWindow: BrowserWindow) => {
|
||||
* old cache dir if it exists.
|
||||
*
|
||||
* Added May 2024, v1.7.0. This migration code can be removed after some time
|
||||
* once most people have upgraded to newer versions.
|
||||
* once most people have upgraded to newer versions (tag: Migration).
|
||||
*/
|
||||
const deleteLegacyDiskCacheDirIfExists = async () => {
|
||||
const removeIfExists = async (dirPath: string) => {
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
import { ffmpegExec } from "./services/ffmpeg";
|
||||
import {
|
||||
fsExists,
|
||||
fsFindFiles,
|
||||
fsIsDir,
|
||||
fsMkdirIfNeeded,
|
||||
fsReadTextFile,
|
||||
@@ -63,7 +64,6 @@ import {
|
||||
} from "./services/upload";
|
||||
import {
|
||||
watchAdd,
|
||||
watchFindFiles,
|
||||
watchGet,
|
||||
watchRemove,
|
||||
watchUpdateIgnoredFiles,
|
||||
@@ -154,6 +154,10 @@ export const attachIPCHandlers = () => {
|
||||
|
||||
ipcMain.handle("fsIsDir", (_, dirPath: string) => fsIsDir(dirPath));
|
||||
|
||||
ipcMain.handle("fsFindFiles", (_, folderPath: string) =>
|
||||
fsFindFiles(folderPath),
|
||||
);
|
||||
|
||||
// - Conversion
|
||||
|
||||
ipcMain.handle("convertToJPEG", (_, imageData: Uint8Array) =>
|
||||
@@ -182,10 +186,8 @@ export const attachIPCHandlers = () => {
|
||||
|
||||
// - ML
|
||||
|
||||
ipcMain.handle(
|
||||
"computeCLIPImageEmbedding",
|
||||
(_, jpegImageData: Uint8Array) =>
|
||||
computeCLIPImageEmbedding(jpegImageData),
|
||||
ipcMain.handle("computeCLIPImageEmbedding", (_, input: Float32Array) =>
|
||||
computeCLIPImageEmbedding(input),
|
||||
);
|
||||
|
||||
ipcMain.handle("computeCLIPTextEmbeddingIfAvailable", (_, text: string) =>
|
||||
@@ -262,10 +264,6 @@ export const attachFSWatchIPCHandlers = (watcher: FSWatcher) => {
|
||||
(_, ignoredFiles: FolderWatch["ignoredFiles"], folderPath: string) =>
|
||||
watchUpdateIgnoredFiles(ignoredFiles, folderPath),
|
||||
);
|
||||
|
||||
ipcMain.handle("watchFindFiles", (_, folderPath: string) =>
|
||||
watchFindFiles(folderPath),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,7 @@ class AutoLauncher {
|
||||
if (this.autoLaunch) {
|
||||
return app.commandLine.hasSwitch("hidden");
|
||||
} else {
|
||||
return app.getLoginItemSettings().openAtLogin;
|
||||
return app.getLoginItemSettings().wasOpenedAtLogin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import { existsSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
export const fsExists = (path: string) => existsSync(path);
|
||||
|
||||
@@ -28,3 +29,17 @@ export const fsIsDir = async (dirPath: string) => {
|
||||
const stat = await fs.stat(dirPath);
|
||||
return stat.isDirectory();
|
||||
};
|
||||
|
||||
export const fsFindFiles = async (dirPath: string) => {
|
||||
const items = await fs.readdir(dirPath, { withFileTypes: true });
|
||||
let paths: string[] = [];
|
||||
for (const item of items) {
|
||||
const itemPath = path.posix.join(dirPath, item.name);
|
||||
if (item.isFile()) {
|
||||
paths.push(itemPath);
|
||||
} else if (item.isDirectory()) {
|
||||
paths = [...paths, ...(await fsFindFiles(itemPath))];
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import log from "../log";
|
||||
import { clearConvertToMP4Results } from "../stream";
|
||||
import { clearStores } from "./store";
|
||||
import { watchReset } from "./watch";
|
||||
import { clearOpenZipCache } from "./zip";
|
||||
|
||||
/**
|
||||
* Perform the native side logout sequence.
|
||||
@@ -30,4 +31,9 @@ export const logout = (watcher: FSWatcher) => {
|
||||
} catch (e) {
|
||||
ignoreError("native stores", e);
|
||||
}
|
||||
try {
|
||||
clearOpenZipCache();
|
||||
} catch (e) {
|
||||
ignoreError("zip cache", e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,17 +2,12 @@
|
||||
* @file Compute CLIP embeddings for images and text.
|
||||
*
|
||||
* The embeddings are computed using ONNX runtime, with CLIP as the model.
|
||||
*
|
||||
* @see `web/apps/photos/src/services/clip-service.ts` for more details.
|
||||
*/
|
||||
import jpeg from "jpeg-js";
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import Tokenizer from "clip-bpe-js";
|
||||
import * as ort from "onnxruntime-node";
|
||||
import Tokenizer from "../../thirdparty/clip-bpe-ts/mod";
|
||||
import log from "../log";
|
||||
import { writeStream } from "../stream";
|
||||
import { ensure, wait } from "../utils/common";
|
||||
import { deleteTempFile, makeTempFilePath } from "../utils/temp";
|
||||
import { makeCachedInferenceSession } from "./ml";
|
||||
|
||||
const cachedCLIPImageSession = makeCachedInferenceSession(
|
||||
@@ -20,113 +15,16 @@ const cachedCLIPImageSession = makeCachedInferenceSession(
|
||||
351468764 /* 335.2 MB */,
|
||||
);
|
||||
|
||||
export const computeCLIPImageEmbedding = async (jpegImageData: Uint8Array) => {
|
||||
const tempFilePath = await makeTempFilePath();
|
||||
const imageStream = new Response(jpegImageData.buffer).body;
|
||||
await writeStream(tempFilePath, ensure(imageStream));
|
||||
try {
|
||||
return await clipImageEmbedding_(tempFilePath);
|
||||
} finally {
|
||||
await deleteTempFile(tempFilePath);
|
||||
}
|
||||
};
|
||||
|
||||
const clipImageEmbedding_ = async (jpegFilePath: string) => {
|
||||
export const computeCLIPImageEmbedding = async (input: Float32Array) => {
|
||||
const session = await cachedCLIPImageSession();
|
||||
const t1 = Date.now();
|
||||
const rgbData = await getRGBData(jpegFilePath);
|
||||
const t = Date.now();
|
||||
const feeds = {
|
||||
input: new ort.Tensor("float32", rgbData, [1, 3, 224, 224]),
|
||||
input: new ort.Tensor("float32", input, [1, 3, 224, 224]),
|
||||
};
|
||||
const t2 = Date.now();
|
||||
const results = await session.run(feeds);
|
||||
log.debug(
|
||||
() =>
|
||||
`ONNX/CLIP image embedding took ${Date.now() - t1} ms (prep: ${t2 - t1} ms, inference: ${Date.now() - t2} ms)`,
|
||||
);
|
||||
log.debug(() => `ONNX/CLIP image embedding took ${Date.now() - t} ms`);
|
||||
/* Need these model specific casts to type the result */
|
||||
const imageEmbedding = ensure(results.output).data as Float32Array;
|
||||
return normalizeEmbedding(imageEmbedding);
|
||||
};
|
||||
|
||||
const getRGBData = async (jpegFilePath: string): Promise<number[]> => {
|
||||
const jpegData = await fs.readFile(jpegFilePath);
|
||||
const rawImageData = jpeg.decode(jpegData, {
|
||||
useTArray: true,
|
||||
formatAsRGBA: false,
|
||||
});
|
||||
|
||||
const nx = rawImageData.width;
|
||||
const ny = rawImageData.height;
|
||||
const inputImage = rawImageData.data;
|
||||
|
||||
const nx2 = 224;
|
||||
const ny2 = 224;
|
||||
const totalSize = 3 * nx2 * ny2;
|
||||
|
||||
const result = Array<number>(totalSize).fill(0);
|
||||
const scale = Math.max(nx, ny) / 224;
|
||||
|
||||
const nx3 = Math.round(nx / scale);
|
||||
const ny3 = Math.round(ny / scale);
|
||||
|
||||
const mean: number[] = [0.48145466, 0.4578275, 0.40821073];
|
||||
const std: number[] = [0.26862954, 0.26130258, 0.27577711];
|
||||
|
||||
for (let y = 0; y < ny3; y++) {
|
||||
for (let x = 0; x < nx3; x++) {
|
||||
for (let c = 0; c < 3; c++) {
|
||||
// Linear interpolation
|
||||
const sx = (x + 0.5) * scale - 0.5;
|
||||
const sy = (y + 0.5) * scale - 0.5;
|
||||
|
||||
const x0 = Math.max(0, Math.floor(sx));
|
||||
const y0 = Math.max(0, Math.floor(sy));
|
||||
|
||||
const x1 = Math.min(x0 + 1, nx - 1);
|
||||
const y1 = Math.min(y0 + 1, ny - 1);
|
||||
|
||||
const dx = sx - x0;
|
||||
const dy = sy - y0;
|
||||
|
||||
const j00 = 3 * (y0 * nx + x0) + c;
|
||||
const j01 = 3 * (y0 * nx + x1) + c;
|
||||
const j10 = 3 * (y1 * nx + x0) + c;
|
||||
const j11 = 3 * (y1 * nx + x1) + c;
|
||||
|
||||
const v00 = inputImage[j00] ?? 0;
|
||||
const v01 = inputImage[j01] ?? 0;
|
||||
const v10 = inputImage[j10] ?? 0;
|
||||
const v11 = inputImage[j11] ?? 0;
|
||||
|
||||
const v0 = v00 * (1 - dx) + v01 * dx;
|
||||
const v1 = v10 * (1 - dx) + v11 * dx;
|
||||
|
||||
const v = v0 * (1 - dy) + v1 * dy;
|
||||
|
||||
const v2 = Math.min(Math.max(Math.round(v), 0), 255);
|
||||
|
||||
// createTensorWithDataList is dumb compared to reshape and
|
||||
// hence has to be given with one channel after another
|
||||
const i = y * nx3 + x + (c % 3) * 224 * 224;
|
||||
|
||||
result[i] = (v2 / 255 - (mean[c] ?? 0)) / (std[c] ?? 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const normalizeEmbedding = (embedding: Float32Array) => {
|
||||
let normalization = 0;
|
||||
for (const v of embedding) normalization += v * v;
|
||||
|
||||
const sqrtNormalization = Math.sqrt(normalization);
|
||||
for (let index = 0; index < embedding.length; index++)
|
||||
embedding[index] = ensure(embedding[index]) / sqrtNormalization;
|
||||
|
||||
return embedding;
|
||||
return ensure(results.output).data as Float32Array;
|
||||
};
|
||||
|
||||
const cachedCLIPTextSession = makeCachedInferenceSession(
|
||||
@@ -157,18 +55,14 @@ export const computeCLIPTextEmbeddingIfAvailable = async (text: string) => {
|
||||
}
|
||||
|
||||
const session = sessionOrSkip;
|
||||
const t1 = Date.now();
|
||||
const t = Date.now();
|
||||
const tokenizer = getTokenizer();
|
||||
const tokenizedText = Int32Array.from(tokenizer.encodeForCLIP(text));
|
||||
const feeds = {
|
||||
input: new ort.Tensor("int32", tokenizedText, [1, 77]),
|
||||
};
|
||||
const t2 = Date.now();
|
||||
|
||||
const results = await session.run(feeds);
|
||||
log.debug(
|
||||
() =>
|
||||
`ONNX/CLIP text embedding took ${Date.now() - t1} ms (prep: ${t2 - t1} ms, inference: ${Date.now() - t2} ms)`,
|
||||
);
|
||||
const textEmbedding = ensure(results.output).data as Float32Array;
|
||||
return normalizeEmbedding(textEmbedding);
|
||||
log.debug(() => `ONNX/CLIP text embedding took ${Date.now() - t} ms`);
|
||||
return ensure(results.output).data as Float32Array;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
* The runtime used is ONNX.
|
||||
*/
|
||||
|
||||
import * as ort from "onnxruntime-node";
|
||||
import log from "../log";
|
||||
import { ensure } from "../utils/common";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file AI/ML related functionality, generic layer.
|
||||
* @file ML related functionality, generic layer.
|
||||
*
|
||||
* @see also `ml-clip.ts`, `ml-face.ts`.
|
||||
*
|
||||
@@ -10,6 +10,7 @@
|
||||
* can use the binary ONNX runtime which is 10-20x faster than the WASM based
|
||||
* web one.
|
||||
*/
|
||||
|
||||
import { app, net } from "electron/main";
|
||||
import { existsSync } from "fs";
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
import StreamZip from "node-stream-zip";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { existsSync } from "original-fs";
|
||||
import type { PendingUploads, ZipItem } from "../../types/ipc";
|
||||
import log from "../log";
|
||||
import { uploadStatusStore } from "../stores/upload-status";
|
||||
import { clearOpenZipCache, markClosableZip, openZip } from "./zip";
|
||||
|
||||
export const listZipItems = async (zipPath: string): Promise<ZipItem[]> => {
|
||||
const zip = new StreamZip.async({ file: zipPath });
|
||||
const zip = openZip(zipPath);
|
||||
|
||||
const entries = await zip.entries();
|
||||
const entryNames: string[] = [];
|
||||
try {
|
||||
const entries = await zip.entries();
|
||||
const entryNames: string[] = [];
|
||||
|
||||
for (const entry of Object.values(entries)) {
|
||||
const basename = path.basename(entry.name);
|
||||
// Ignore "hidden" files (files whose names begins with a dot).
|
||||
if (entry.isFile && !basename.startsWith(".")) {
|
||||
// `entry.name` is the path within the zip.
|
||||
entryNames.push(entry.name);
|
||||
for (const entry of Object.values(entries)) {
|
||||
const basename = path.basename(entry.name);
|
||||
// Ignore "hidden" files (files whose names begins with a dot).
|
||||
if (entry.isFile && !basename.startsWith(".")) {
|
||||
// `entry.name` is the path within the zip.
|
||||
entryNames.push(entry.name);
|
||||
}
|
||||
}
|
||||
return entryNames.map((entryName) => [zipPath, entryName]);
|
||||
} finally {
|
||||
markClosableZip(zipPath);
|
||||
}
|
||||
|
||||
await zip.close();
|
||||
|
||||
return entryNames.map((entryName) => [zipPath, entryName]);
|
||||
};
|
||||
|
||||
export const pathOrZipItemSize = async (
|
||||
@@ -34,15 +35,17 @@ export const pathOrZipItemSize = async (
|
||||
return stat.size;
|
||||
} else {
|
||||
const [zipPath, entryName] = pathOrZipItem;
|
||||
const zip = new StreamZip.async({ file: zipPath });
|
||||
const entry = await zip.entry(entryName);
|
||||
if (!entry)
|
||||
throw new Error(
|
||||
`An entry with name ${entryName} does not exist in the zip file at ${zipPath}`,
|
||||
);
|
||||
const size = entry.size;
|
||||
await zip.close();
|
||||
return size;
|
||||
const zip = openZip(zipPath);
|
||||
try {
|
||||
const entry = await zip.entry(entryName);
|
||||
if (!entry)
|
||||
throw new Error(
|
||||
`An entry with name ${entryName} does not exist in the zip file at ${zipPath}`,
|
||||
);
|
||||
return entry.size;
|
||||
} finally {
|
||||
markClosableZip(zipPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,7 +58,7 @@ export const pendingUploads = async (): Promise<PendingUploads | undefined> => {
|
||||
const allZipItems = uploadStatusStore.get("zipItems");
|
||||
let zipItems: typeof allZipItems;
|
||||
|
||||
// Migration code - May 2024. Remove after a bit.
|
||||
// Migration code - May 2024. Remove after a bit (tag: Migration).
|
||||
//
|
||||
// The older store formats will not have zipItems and instead will have
|
||||
// zipPaths. If we find such a case, read the zipPaths and enqueue all of
|
||||
@@ -152,4 +155,7 @@ export const markUploadedZipItems = (
|
||||
uploadStatusStore.set("zipItems", updated);
|
||||
};
|
||||
|
||||
export const clearPendingUploads = () => uploadStatusStore.clear();
|
||||
export const clearPendingUploads = () => {
|
||||
uploadStatusStore.clear();
|
||||
clearOpenZipCache();
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import chokidar, { type FSWatcher } from "chokidar";
|
||||
import { BrowserWindow } from "electron/main";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { FolderWatch, type CollectionMapping } from "../../types/ipc";
|
||||
import log from "../log";
|
||||
import { watchStore } from "../stores/watch";
|
||||
@@ -143,20 +141,6 @@ export const watchUpdateIgnoredFiles = (
|
||||
);
|
||||
};
|
||||
|
||||
export const watchFindFiles = async (dirPath: string) => {
|
||||
const items = await fs.readdir(dirPath, { withFileTypes: true });
|
||||
let paths: string[] = [];
|
||||
for (const item of items) {
|
||||
const itemPath = path.posix.join(dirPath, item.name);
|
||||
if (item.isFile()) {
|
||||
paths.push(itemPath);
|
||||
} else if (item.isDirectory()) {
|
||||
paths = [...paths, ...(await watchFindFiles(itemPath))];
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop watching all existing folder watches and remove any callbacks.
|
||||
*
|
||||
|
||||
74
desktop/src/main/services/zip.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { LRUCache } from "lru-cache";
|
||||
import StreamZip from "node-stream-zip";
|
||||
|
||||
/** The cache. */
|
||||
const _cache = new LRUCache<string, StreamZip.StreamZipAsync>({
|
||||
max: 50,
|
||||
disposeAfter: (zip, zipPath) => {
|
||||
if (_refCount.has(zipPath)) {
|
||||
// Add it back again.
|
||||
_cache.set(zipPath, zip);
|
||||
} else {
|
||||
void zip.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/** Reference count. */
|
||||
const _refCount = new Map<string, number>();
|
||||
|
||||
/**
|
||||
* Cached `StreamZip.async`s
|
||||
*
|
||||
* This function uses an LRU cache to cache handles to zip files indexed by
|
||||
* their path.
|
||||
*
|
||||
* To clear the cache (which is a good idea to avoid having open file handles
|
||||
* lying around), use {@link clearOpenZipCache}.
|
||||
*
|
||||
* Why was this needed
|
||||
* -------------------
|
||||
*
|
||||
* Caching the StreamZip file handles _significantly_ (hours => seconds)
|
||||
* improves the performance of the metadata parsing step during import of large
|
||||
* Google Takeout zips.
|
||||
*
|
||||
* In ad-hoc tests, it seems that beyond a certain zip size (few GBs), reopening
|
||||
* the handle to a stream zip overshadows the time taken to read the individual
|
||||
* JSONs.
|
||||
*/
|
||||
export const openZip = (zipPath: string) => {
|
||||
let result = _cache.get(zipPath);
|
||||
if (!result) {
|
||||
result = new StreamZip.async({ file: zipPath });
|
||||
_cache.set(zipPath, result);
|
||||
}
|
||||
_refCount.set(zipPath, (_refCount.get(zipPath) ?? 0) + 1);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicate to our cache that an item we opened earlier using {@link openZip}
|
||||
* can now be safely closed.
|
||||
*
|
||||
* @param zipPath The key that was used for opening this zip.
|
||||
*/
|
||||
export const markClosableZip = (zipPath: string) => {
|
||||
const rc = _refCount.get(zipPath);
|
||||
if (!rc) throw new Error(`Double close for ${zipPath}`);
|
||||
if (rc == 1) _refCount.delete(zipPath);
|
||||
else _refCount.set(zipPath, rc - 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear any entries previously cached by {@link openZip}.
|
||||
*/
|
||||
export const clearOpenZipCache = () => {
|
||||
if (_refCount.size > 0) {
|
||||
const keys = JSON.stringify([..._refCount.keys()]);
|
||||
throw new Error(
|
||||
`Attempting to clear zip file cache when some items are still in use: ${keys}`,
|
||||
);
|
||||
}
|
||||
_cache.clear();
|
||||
};
|
||||
@@ -2,7 +2,6 @@
|
||||
* @file stream data to-from renderer using a custom protocol handler.
|
||||
*/
|
||||
import { net, protocol } from "electron/main";
|
||||
import StreamZip from "node-stream-zip";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { createWriteStream, existsSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
@@ -11,6 +10,7 @@ import { ReadableStream } from "node:stream/web";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import log from "./log";
|
||||
import { ffmpegConvertToMP4 } from "./services/ffmpeg";
|
||||
import { markClosableZip, openZip } from "./services/zip";
|
||||
import { ensure } from "./utils/common";
|
||||
import {
|
||||
deleteTempFile,
|
||||
@@ -113,14 +113,17 @@ const handleRead = async (path: string) => {
|
||||
};
|
||||
|
||||
const handleReadZip = async (zipPath: string, entryName: string) => {
|
||||
const zip = new StreamZip.async({ file: zipPath });
|
||||
const zip = openZip(zipPath);
|
||||
const entry = await zip.entry(entryName);
|
||||
if (!entry) return new Response("", { status: 404 });
|
||||
if (!entry) {
|
||||
markClosableZip(zipPath);
|
||||
return new Response("", { status: 404 });
|
||||
}
|
||||
|
||||
// This returns an "old style" NodeJS.ReadableStream.
|
||||
const stream = await zip.stream(entry);
|
||||
// Convert it into a new style NodeJS.Readable.
|
||||
const nodeReadable = new Readable().wrap(stream);
|
||||
const nodeReadable = new Readable({ emitClose: true }).wrap(stream);
|
||||
// Then convert it into a Web stream.
|
||||
const webReadableStreamAny = Readable.toWeb(nodeReadable);
|
||||
// However, we get a ReadableStream<any> now. This doesn't go into the
|
||||
@@ -129,8 +132,8 @@ const handleReadZip = async (zipPath: string, entryName: string) => {
|
||||
const webReadableStream =
|
||||
webReadableStreamAny as ReadableStream<Uint8Array>;
|
||||
|
||||
// Close the zip handle when the underlying stream closes.
|
||||
stream.on("end", () => void zip.close());
|
||||
// Let go of the zip handle when the underlying stream closes.
|
||||
nodeReadable.on("close", () => markClosableZip(zipPath));
|
||||
|
||||
// While it is documented that entry.time is the modification time,
|
||||
// the units are not mentioned. By seeing the source code, we can
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { app } from "electron/main";
|
||||
import StreamZip from "node-stream-zip";
|
||||
import { existsSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { ZipItem } from "../../types/ipc";
|
||||
import log from "../log";
|
||||
import { markClosableZip, openZip } from "../services/zip";
|
||||
import { ensure } from "./common";
|
||||
|
||||
/**
|
||||
@@ -128,9 +128,12 @@ export const makeFileForDataOrPathOrZipItem = async (
|
||||
} else {
|
||||
writeToTemporaryFile = async () => {
|
||||
const [zipPath, entryName] = dataOrPathOrZipItem;
|
||||
const zip = new StreamZip.async({ file: zipPath });
|
||||
await zip.extract(entryName, path);
|
||||
await zip.close();
|
||||
const zip = openZip(zipPath);
|
||||
try {
|
||||
await zip.extract(entryName, path);
|
||||
} finally {
|
||||
markClosableZip(zipPath);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,8 +163,8 @@ const ffmpegExec = (
|
||||
|
||||
// - ML
|
||||
|
||||
const computeCLIPImageEmbedding = (jpegImageData: Uint8Array) =>
|
||||
ipcRenderer.invoke("computeCLIPImageEmbedding", jpegImageData);
|
||||
const computeCLIPImageEmbedding = (input: Float32Array) =>
|
||||
ipcRenderer.invoke("computeCLIPImageEmbedding", input);
|
||||
|
||||
const computeCLIPTextEmbeddingIfAvailable = (text: string) =>
|
||||
ipcRenderer.invoke("computeCLIPTextEmbeddingIfAvailable", text);
|
||||
@@ -216,8 +216,8 @@ const watchOnRemoveDir = (f: (path: string, watch: FolderWatch) => void) => {
|
||||
);
|
||||
};
|
||||
|
||||
const watchFindFiles = (folderPath: string) =>
|
||||
ipcRenderer.invoke("watchFindFiles", folderPath);
|
||||
const fsFindFiles = (folderPath: string) =>
|
||||
ipcRenderer.invoke("fsFindFiles", folderPath);
|
||||
|
||||
const watchRemoveListeners = () => {
|
||||
ipcRenderer.removeAllListeners("watchAddFile");
|
||||
@@ -340,6 +340,7 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
readTextFile: fsReadTextFile,
|
||||
writeFile: fsWriteFile,
|
||||
isDir: fsIsDir,
|
||||
findFiles: fsFindFiles,
|
||||
},
|
||||
|
||||
// - Conversion
|
||||
@@ -366,7 +367,6 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
onAddFile: watchOnAddFile,
|
||||
onRemoveFile: watchOnRemoveFile,
|
||||
onRemoveDir: watchOnRemoveDir,
|
||||
findFiles: watchFindFiles,
|
||||
},
|
||||
|
||||
// - Upload
|
||||
|
||||
21
desktop/src/thirdparty/clip-bpe-ts/LICENSE
vendored
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 josephrocca
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
40
desktop/src/thirdparty/clip-bpe-ts/README.md
vendored
@@ -1,40 +0,0 @@
|
||||
# CLIP Byte Pair Encoding JavaScript Port
|
||||
|
||||
A JavaScript port of
|
||||
[OpenAI's CLIP byte-pair-encoding tokenizer](https://github.com/openai/CLIP/blob/3bee28119e6b28e75b82b811b87b56935314e6a5/clip/simple_tokenizer.py).
|
||||
|
||||
```js
|
||||
import Tokenizer from "https://deno.land/x/clip_bpe@v0.0.6/mod.js";
|
||||
let t = new Tokenizer();
|
||||
|
||||
t.encode("hello"); // [3306]
|
||||
t.encode("magnificent"); // [10724]
|
||||
t.encode("magnificently"); // [9725, 2922]
|
||||
t.decode(t.encode("HELLO")); // "hello "
|
||||
t.decode(t.encode("abc123")); // "abc 1 2 3 "
|
||||
t.decode(st.encode("let's see here")); // "let 's see here "
|
||||
t.encode("hello world!"); // [3306, 1002, 256]
|
||||
|
||||
// to encode for CLIP (trims to maximum of 77 tokens and adds start and end token, and pads with zeros if less than 77 tokens):
|
||||
t.encodeForCLIP("hello world!"); // [49406,3306,1002,256,49407,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
|
||||
```
|
||||
|
||||
This encoder/decoder behaves differently to the the GPT-2/3 tokenizer
|
||||
(JavaScript version of that
|
||||
[here](https://github.com/latitudegames/GPT-3-Encoder)). For example, it doesn't
|
||||
preserve capital letters, as shown above.
|
||||
|
||||
The
|
||||
[Python version](https://github.com/openai/CLIP/blob/3bee28119e6b28e75b82b811b87b56935314e6a5/clip/simple_tokenizer.py)
|
||||
of this tokenizer uses the `ftfy` module to clean up the text before encoding
|
||||
it. I didn't include that module by default because currently the only version
|
||||
available in JavaScript is
|
||||
[this one](https://github.com/josephrocca/ftfy-pyodide), which requires
|
||||
importing a full Python runtime as a WebAssembly module. If you want the `ftfy`
|
||||
cleaning, just import it and clean your text with it before passing it to the
|
||||
`.encode()` method.
|
||||
|
||||
# License
|
||||
|
||||
To the extent that there is any original work in this repo, it is MIT Licensed,
|
||||
just like [openai/CLIP](https://github.com/openai/CLIP).
|
||||
470
desktop/src/thirdparty/clip-bpe-ts/mod.ts
vendored
@@ -1,470 +0,0 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import * as htmlEntities from "html-entities";
|
||||
import bpeVocabData from "./bpe_simple_vocab_16e6";
|
||||
// import ftfy from "https://deno.land/x/ftfy_pyodide@v0.1.1/mod.js";
|
||||
|
||||
function ord(c: string) {
|
||||
return c.charCodeAt(0);
|
||||
}
|
||||
function range(start: number, stop?: number, step: number = 1) {
|
||||
if (stop === undefined) {
|
||||
stop = start;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const result: number[] = [];
|
||||
for (let i = start; step > 0 ? i < stop : i > stop; i += step) {
|
||||
result.push(i);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function bytesToUnicode() {
|
||||
const bs = [
|
||||
...range(ord("!"), ord("~") + 1),
|
||||
...range(ord("¡"), ord("¬") + 1),
|
||||
...range(ord("®"), ord("ÿ") + 1),
|
||||
];
|
||||
const cs = bs.slice(0);
|
||||
let n = 0;
|
||||
for (const b of range(2 ** 8)) {
|
||||
if (!bs.includes(b)) {
|
||||
bs.push(b);
|
||||
cs.push(2 ** 8 + n);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
const csString = cs.map((n) => String.fromCharCode(n));
|
||||
return Object.fromEntries(bs.map((v, i) => [v, csString[i]]));
|
||||
}
|
||||
|
||||
function getPairs(word: string | any[]) {
|
||||
const pairs: [string, string][] = [];
|
||||
let prevChar = word[0];
|
||||
for (const char of word.slice(1)) {
|
||||
pairs.push([prevChar, char]);
|
||||
prevChar = char;
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
function basicClean(text: string) {
|
||||
// text = ftfy.fix_text(text);
|
||||
text = htmlEntities.decode(htmlEntities.decode(text));
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
function whitespaceClean(text: string) {
|
||||
return text.replace(/\s+/g, " ").trim();
|
||||
}
|
||||
|
||||
export default class {
|
||||
byteEncoder;
|
||||
byteDecoder: {
|
||||
[k: string]: number;
|
||||
};
|
||||
encoder;
|
||||
decoder: any;
|
||||
bpeRanks: any;
|
||||
cache: Record<string, string>;
|
||||
pat: RegExp;
|
||||
constructor() {
|
||||
this.byteEncoder = bytesToUnicode();
|
||||
this.byteDecoder = Object.fromEntries(
|
||||
Object.entries(this.byteEncoder).map(([k, v]) => [v, Number(k)]),
|
||||
);
|
||||
let merges = bpeVocabData.text.split("\n");
|
||||
merges = merges.slice(1, 49152 - 256 - 2 + 1);
|
||||
const mergedMerges = merges.map((merge) => merge.split(" "));
|
||||
// There was a bug related to the ordering of Python's .values() output. I'm lazy do I've just copy-pasted the Python output:
|
||||
let vocab = [
|
||||
"!",
|
||||
'"',
|
||||
"#",
|
||||
"$",
|
||||
"%",
|
||||
"&",
|
||||
"'",
|
||||
"(",
|
||||
")",
|
||||
"*",
|
||||
"+",
|
||||
",",
|
||||
"-",
|
||||
".",
|
||||
"/",
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
":",
|
||||
";",
|
||||
"<",
|
||||
"=",
|
||||
">",
|
||||
"?",
|
||||
"@",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"[",
|
||||
"\\",
|
||||
"]",
|
||||
"^",
|
||||
"_",
|
||||
"`",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"{",
|
||||
"|",
|
||||
"}",
|
||||
"~",
|
||||
"¡",
|
||||
"¢",
|
||||
"£",
|
||||
"¤",
|
||||
"¥",
|
||||
"¦",
|
||||
"§",
|
||||
"¨",
|
||||
"©",
|
||||
"ª",
|
||||
"«",
|
||||
"¬",
|
||||
"®",
|
||||
"¯",
|
||||
"°",
|
||||
"±",
|
||||
"²",
|
||||
"³",
|
||||
"´",
|
||||
"µ",
|
||||
"¶",
|
||||
"·",
|
||||
"¸",
|
||||
"¹",
|
||||
"º",
|
||||
"»",
|
||||
"¼",
|
||||
"½",
|
||||
"¾",
|
||||
"¿",
|
||||
"À",
|
||||
"Á",
|
||||
"Â",
|
||||
"Ã",
|
||||
"Ä",
|
||||
"Å",
|
||||
"Æ",
|
||||
"Ç",
|
||||
"È",
|
||||
"É",
|
||||
"Ê",
|
||||
"Ë",
|
||||
"Ì",
|
||||
"Í",
|
||||
"Î",
|
||||
"Ï",
|
||||
"Ð",
|
||||
"Ñ",
|
||||
"Ò",
|
||||
"Ó",
|
||||
"Ô",
|
||||
"Õ",
|
||||
"Ö",
|
||||
"×",
|
||||
"Ø",
|
||||
"Ù",
|
||||
"Ú",
|
||||
"Û",
|
||||
"Ü",
|
||||
"Ý",
|
||||
"Þ",
|
||||
"ß",
|
||||
"à",
|
||||
"á",
|
||||
"â",
|
||||
"ã",
|
||||
"ä",
|
||||
"å",
|
||||
"æ",
|
||||
"ç",
|
||||
"è",
|
||||
"é",
|
||||
"ê",
|
||||
"ë",
|
||||
"ì",
|
||||
"í",
|
||||
"î",
|
||||
"ï",
|
||||
"ð",
|
||||
"ñ",
|
||||
"ò",
|
||||
"ó",
|
||||
"ô",
|
||||
"õ",
|
||||
"ö",
|
||||
"÷",
|
||||
"ø",
|
||||
"ù",
|
||||
"ú",
|
||||
"û",
|
||||
"ü",
|
||||
"ý",
|
||||
"þ",
|
||||
"ÿ",
|
||||
"Ā",
|
||||
"ā",
|
||||
"Ă",
|
||||
"ă",
|
||||
"Ą",
|
||||
"ą",
|
||||
"Ć",
|
||||
"ć",
|
||||
"Ĉ",
|
||||
"ĉ",
|
||||
"Ċ",
|
||||
"ċ",
|
||||
"Č",
|
||||
"č",
|
||||
"Ď",
|
||||
"ď",
|
||||
"Đ",
|
||||
"đ",
|
||||
"Ē",
|
||||
"ē",
|
||||
"Ĕ",
|
||||
"ĕ",
|
||||
"Ė",
|
||||
"ė",
|
||||
"Ę",
|
||||
"ę",
|
||||
"Ě",
|
||||
"ě",
|
||||
"Ĝ",
|
||||
"ĝ",
|
||||
"Ğ",
|
||||
"ğ",
|
||||
"Ġ",
|
||||
"ġ",
|
||||
"Ģ",
|
||||
"ģ",
|
||||
"Ĥ",
|
||||
"ĥ",
|
||||
"Ħ",
|
||||
"ħ",
|
||||
"Ĩ",
|
||||
"ĩ",
|
||||
"Ī",
|
||||
"ī",
|
||||
"Ĭ",
|
||||
"ĭ",
|
||||
"Į",
|
||||
"į",
|
||||
"İ",
|
||||
"ı",
|
||||
"IJ",
|
||||
"ij",
|
||||
"Ĵ",
|
||||
"ĵ",
|
||||
"Ķ",
|
||||
"ķ",
|
||||
"ĸ",
|
||||
"Ĺ",
|
||||
"ĺ",
|
||||
"Ļ",
|
||||
"ļ",
|
||||
"Ľ",
|
||||
"ľ",
|
||||
"Ŀ",
|
||||
"ŀ",
|
||||
"Ł",
|
||||
"ł",
|
||||
"Ń",
|
||||
];
|
||||
vocab = [...vocab, ...vocab.map((v) => v + "</w>")];
|
||||
for (const merge of mergedMerges) {
|
||||
vocab.push(merge.join(""));
|
||||
}
|
||||
vocab.push("<|startoftext|>", "<|endoftext|>");
|
||||
this.encoder = Object.fromEntries(vocab.map((v, i) => [v, i]));
|
||||
this.decoder = Object.fromEntries(
|
||||
Object.entries(this.encoder).map(([k, v]) => [v, k]),
|
||||
);
|
||||
this.bpeRanks = Object.fromEntries(
|
||||
mergedMerges.map((v, i) => [v.join("·😎·"), i]),
|
||||
); // ·😎· because js doesn't yet have tuples
|
||||
this.cache = {
|
||||
"<|startoftext|>": "<|startoftext|>",
|
||||
"<|endoftext|>": "<|endoftext|>",
|
||||
};
|
||||
this.pat =
|
||||
/<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+/giu;
|
||||
}
|
||||
|
||||
bpe(token: string) {
|
||||
if (this.cache[token] !== undefined) {
|
||||
return this.cache[token];
|
||||
}
|
||||
|
||||
let word = [...token.slice(0, -1), token.slice(-1) + "</w>"];
|
||||
let pairs = getPairs(word);
|
||||
|
||||
if (pairs.length === 0) {
|
||||
return token + "</w>";
|
||||
}
|
||||
|
||||
while (1) {
|
||||
let bigram: [string, string] | null = null;
|
||||
let minRank = Infinity;
|
||||
for (const p of pairs) {
|
||||
const r = this.bpeRanks[p.join("·😎·")];
|
||||
if (r === undefined) continue;
|
||||
if (r < minRank) {
|
||||
minRank = r;
|
||||
bigram = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (bigram === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
const [first, second] = bigram;
|
||||
const newWord: string[] = [];
|
||||
let i = 0;
|
||||
while (i < word.length) {
|
||||
const j = word.indexOf(first, i);
|
||||
|
||||
if (j === -1) {
|
||||
newWord.push(...word.slice(i));
|
||||
break;
|
||||
}
|
||||
|
||||
newWord.push(...word.slice(i, j));
|
||||
i = j;
|
||||
|
||||
if (
|
||||
word[i] === first &&
|
||||
i < word.length - 1 &&
|
||||
word[i + 1] === second
|
||||
) {
|
||||
newWord.push(first + second);
|
||||
i += 2;
|
||||
} else {
|
||||
// @ts-expect-error "Array indexing can return undefined but not modifying thirdparty code"
|
||||
newWord.push(word[i]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
word = newWord;
|
||||
if (word.length === 1) {
|
||||
break;
|
||||
} else {
|
||||
pairs = getPairs(word);
|
||||
}
|
||||
}
|
||||
const joinedWord = word.join(" ");
|
||||
this.cache[token] = joinedWord;
|
||||
return joinedWord;
|
||||
}
|
||||
|
||||
encode(text: string) {
|
||||
const bpeTokens: number[] = [];
|
||||
text = whitespaceClean(basicClean(text)).toLowerCase();
|
||||
for (let token of [...text.matchAll(this.pat)].map((m) => m[0])) {
|
||||
token = [...token]
|
||||
.map((b) => this.byteEncoder[b.charCodeAt(0) as number])
|
||||
.join("");
|
||||
bpeTokens.push(
|
||||
// @ts-expect-error "Array indexing can return undefined but not modifying thirdparty code"
|
||||
...this.bpe(token)
|
||||
.split(" ")
|
||||
.map((bpeToken: string) => this.encoder[bpeToken]),
|
||||
);
|
||||
}
|
||||
return bpeTokens;
|
||||
}
|
||||
|
||||
// adds start and end token, and adds padding 0's and ensures it's 77 tokens long
|
||||
encodeForCLIP(text: string) {
|
||||
let tokens = this.encode(text);
|
||||
tokens.unshift(49406); // start token
|
||||
tokens = tokens.slice(0, 76);
|
||||
tokens.push(49407); // end token
|
||||
while (tokens.length < 77) tokens.push(0);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
decode(tokens: any[]) {
|
||||
let text = tokens
|
||||
.map((token: string | number) => this.decoder[token])
|
||||
.join("");
|
||||
text = [...text]
|
||||
.map((c) => this.byteDecoder[c])
|
||||
// @ts-expect-error "Array indexing can return undefined but not modifying thirdparty code"
|
||||
.map((v) => String.fromCharCode(v))
|
||||
.join("")
|
||||
.replace(/<\/w>/g, " ");
|
||||
return text;
|
||||
}
|
||||
}
|
||||
11
desktop/src/types/clip-bpe-js.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @file Types for "clip-bpe-js"
|
||||
*
|
||||
* Non exhaustive, only the function we need.
|
||||
*/
|
||||
|
||||
declare module "clip-bpe-js" {
|
||||
class Tokenizer {
|
||||
encodeForCLIP(text: string): number[];
|
||||
}
|
||||
}
|
||||
@@ -117,19 +117,24 @@
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1":
|
||||
"@eslint-community/regexpp@^4.10.0":
|
||||
version "4.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
|
||||
integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
|
||||
|
||||
"@eslint/config-array@^0.15.1":
|
||||
version "0.15.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.15.1.tgz#1fa78b422d98f4e7979f2211a1fde137e26c7d61"
|
||||
integrity sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==
|
||||
"@eslint-community/regexpp@^4.6.1":
|
||||
version "4.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae"
|
||||
integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==
|
||||
|
||||
"@eslint/config-array@^0.17.0":
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.17.0.tgz#ff305e1ee618a00e6e5d0485454c8d92d94a860d"
|
||||
integrity sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==
|
||||
dependencies:
|
||||
"@eslint/object-schema" "^2.1.3"
|
||||
"@eslint/object-schema" "^2.1.4"
|
||||
debug "^4.3.1"
|
||||
minimatch "^3.0.5"
|
||||
minimatch "^3.1.2"
|
||||
|
||||
"@eslint/eslintrc@^3.1.0":
|
||||
version "3.1.0"
|
||||
@@ -146,15 +151,15 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@9.4.0", "@eslint/js@^9.4.0":
|
||||
version "9.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.4.0.tgz#96a2edd37ec0551ce5f9540705be23951c008a0c"
|
||||
integrity sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==
|
||||
"@eslint/js@9.6.0", "@eslint/js@^9":
|
||||
version "9.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.6.0.tgz#5b0cb058cc13d9c92d4e561d3538807fa5127c95"
|
||||
integrity sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==
|
||||
|
||||
"@eslint/object-schema@^2.1.3":
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.3.tgz#e65ae80ee2927b4fd8c5c26b15ecacc2b2a6cc2a"
|
||||
integrity sha512-HAbhAYKfsAC2EkTqve00ibWIZlaU74Z1EHwAjYr4PXF0YU2VEA1zSIKSSpKszRLRWwHzzRZXvK632u+uXzvsvw==
|
||||
"@eslint/object-schema@^2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843"
|
||||
integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
|
||||
|
||||
"@gar/promisify@^1.1.3":
|
||||
version "1.1.3"
|
||||
@@ -323,7 +328,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
|
||||
integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==
|
||||
|
||||
"@types/json-schema@*", "@types/json-schema@^7.0.15":
|
||||
"@types/json-schema@*":
|
||||
version "7.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
@@ -341,9 +346,9 @@
|
||||
integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
|
||||
|
||||
"@types/node@*", "@types/node@^20.9.0":
|
||||
version "20.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.13.0.tgz#011a76bc1e71ae9a026dddcfd7039084f752c4b6"
|
||||
integrity sha512-FM6AOb3khNkNIXPnHFDYaHerSv8uN22C91z098AnGccVu+Pcdhi+pNUFDi0iLmPIsVE0JBD0KVS7mzUYt4nRzQ==
|
||||
version "20.14.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.9.tgz#12e8e765ab27f8c421a1820c99f5f313a933b420"
|
||||
integrity sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
@@ -367,11 +372,6 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/semver@^7.5.8":
|
||||
version "7.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
|
||||
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
|
||||
|
||||
"@types/verror@^1.10.3":
|
||||
version "1.10.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.10.tgz#d5a4b56abac169bfbc8b23d291363a682e6fa087"
|
||||
@@ -384,64 +384,62 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.10.tgz#a102e40da7b72a2981cb2da43064d9b3c865ca58"
|
||||
integrity sha512-jsNKqn41nIS8jz5Li5xsueGEBBmRYLaflUKlclEkj8cWrO1tMK1/7xITeiVz7ZlNFZF2nop2NlXrbLtRpLEzhg==
|
||||
"@typescript-eslint/eslint-plugin@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.39.tgz#1cfd6fe38752ed56d37170d307c48a34c15f65de"
|
||||
integrity sha512-ILv1vDA8M9ah1vzYpnOs4UOLRdB63Ki/rsxedVikjMLq68hFfpsDR25bdMZ4RyUkzLJwOhcg3Jujm/C1nupXKA==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/type-utils" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.10"
|
||||
debug "^4.3.4"
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/type-utils" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.39"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.3.1"
|
||||
natural-compare "^1.4.0"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/parser@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.0.0-alpha.10.tgz#fbefd39da010d65407b985f2b5c6e0a79bc8a6f4"
|
||||
integrity sha512-4EerPviLfBKgExHARehJgWrCtX2a7+PXBc0LBPlH93ypSgj0LU1ejMgjrB0gcfd6bJ7LN/UGNAAy3B7/Y785sA==
|
||||
"@typescript-eslint/parser@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.0.0-alpha.39.tgz#33fbd1e3767b4477def582ce597b6cd09bb5ef11"
|
||||
integrity sha512-5k+pwV91plJojHgZkWlq4/TQdOrnEaeSvt48V0m8iEwdMJqX/63BXYxy8BUOSghWcjp05s73vy9HJjovAKmHkQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.39"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.10.tgz#25506ce51ab64e99f2bc0b7d3f0f82656e14a794"
|
||||
integrity sha512-SUU0yhqehjuWilWRJWfhcxf6eMKVrZ3bpV2w6NF6GmBHR3FJo6oWZYLVXP04s6//INxpC2ynvKSglo4LRzWVTw==
|
||||
"@typescript-eslint/scope-manager@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.39.tgz#1778198dcf95175b76631f7ffd84917bf925a1a9"
|
||||
integrity sha512-HCBlKQROY+JIgWolucdFMj1W3VUnnIQTdxAhxJTAj3ix2nASmvKIFgrdo5KQMrXxQj6tC4l3zva10L+s0dUIIw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.39"
|
||||
|
||||
"@typescript-eslint/type-utils@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.10.tgz#d27f0fdd81450380887b3a07297440ba3588a70e"
|
||||
integrity sha512-6aTcbnDZWKgKr3gquECJSFyvXWLSKtUHrk2ZXDP4DEzmzTDjrkY7tIQpqv4SczPQJ+3/aky3ArPhtnQYJbAMzg==
|
||||
"@typescript-eslint/type-utils@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.39.tgz#48bcc5dc978173e02c44d7137d16edb97042c02d"
|
||||
integrity sha512-alO13fRU6yVeJbwl9ESI3AYhq5dQdz3Dpd0I5B4uezs2lvgYp44dZsj5hWyPz/kL7JFEsjbn+4b/CZA0OQJzjA==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.39"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/types@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.0.0-alpha.10.tgz#89be400c6a1751fe86f5917ed8087ec100e002da"
|
||||
integrity sha512-prbN+b/I4yH6H43WmyenMz8K5e34Hs73BQuWXR4wwij3Cg2xNGLPcpjr2cKWKlH4dZQPTz6R6oBeC+LfaoKi8g==
|
||||
"@typescript-eslint/types@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.0.0-alpha.39.tgz#e0f7618c17f03fc23803269807c77ce1bac276f2"
|
||||
integrity sha512-yINN7j0/+S1VGSp0IgH52oQvUx49vkOug6xbrDA/9o+U55yCAQKSvYWvzYjNa+SZE3hXI0zwvYtMVsIAAMmKIQ==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.10.tgz#e850056d2a5029688269a60206dec3bbd7beb953"
|
||||
integrity sha512-8wBUIhu6IRa440hv5/0ZEnb5JLp/UsfzIXYKRwICUOMTVj2ss1n+w3m1CtT5ghVWy5Z05qkscsbhlKFmZguU8w==
|
||||
"@typescript-eslint/typescript-estree@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.39.tgz#460b2303e3c919cb3baf4ff5a13b6fb148da70b3"
|
||||
integrity sha512-S8gREuP8r8PCxGegeojeXntx0P50ul9YH7c7JYpbLIIsEPNr5f7UHlm+I1NUbL04CBin4kvZ60TG4eWr/KKN9A==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.39"
|
||||
debug "^4.3.4"
|
||||
globby "^11.1.0"
|
||||
is-glob "^4.0.3"
|
||||
@@ -449,25 +447,22 @@
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/utils@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.0.0-alpha.10.tgz#b77f743227353bfa493e95409c0e079044c9258e"
|
||||
integrity sha512-WZyNf49CuvaW/whz/B8XjYwXE/wm/EQAXq+Vqgp6BrJb8SC3bMCwGuUxReNDN1o+dNdOC96ofVSvqa8NUQ65Jg==
|
||||
"@typescript-eslint/utils@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.0.0-alpha.39.tgz#fb27dc504d7fe47fd7e1162b5012e4ce883b40b9"
|
||||
integrity sha512-Nr2PrlfNhrNQTlFHlD7XJdTGw/Vt8qY44irk6bfjn9LxGdSG5e4c1R2UN6kvGMhhx20DBPbM7q3Z3r+huzmL1w==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@types/json-schema" "^7.0.15"
|
||||
"@types/semver" "^7.5.8"
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.10"
|
||||
semver "^7.6.0"
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.39"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.0.0-alpha.10":
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.10.tgz#d0a9250c69cc2f73c7f423c36183d222a329e260"
|
||||
integrity sha512-UohTNnT7S29uQgXsGZY489nWmoBBSJucNdRvog62R1QX9pQQb2pKVV1kHepUxoY2vd+M4tb9SQwZQ3gPNgqQ6w==
|
||||
"@typescript-eslint/visitor-keys@8.0.0-alpha.39":
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.39.tgz#8bf3938fddad4a00eb354880880237abfb55bda5"
|
||||
integrity sha512-DVJ0UdhucZy+/1GlIy7FX2+CFhCeNAi4VwaEAe7u2UDenQr9/kGqvzx00UlpWibmEVDw4KsPOI7Aqa1+2Vqfmw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.39"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@xmldom/xmldom@^0.8.8":
|
||||
@@ -485,10 +480,10 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
acorn@^8.11.3:
|
||||
version "8.11.3"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
|
||||
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
||||
acorn@^8.12.0:
|
||||
version "8.12.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248"
|
||||
integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
|
||||
|
||||
agent-base@6, agent-base@^6.0.2:
|
||||
version "6.0.2"
|
||||
@@ -928,6 +923,11 @@ cli-truncate@^2.1.0:
|
||||
slice-ansi "^3.0.0"
|
||||
string-width "^4.2.0"
|
||||
|
||||
clip-bpe-js@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/clip-bpe-js/-/clip-bpe-js-0.0.6.tgz#a11c228e793fa29841f8cd4f8576fc1ff3403511"
|
||||
integrity sha512-+0n0eeacgFmg9hKhHhXanKkRDhqRwzYK7dj46VYMzePxmN8zbbDgeTQZchfvARNpbBMRi7FfWRSW3lysOUDX/Q==
|
||||
|
||||
cliui@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
|
||||
@@ -1067,6 +1067,13 @@ crc@^3.8.0:
|
||||
dependencies:
|
||||
buffer "^5.1.0"
|
||||
|
||||
cross-env@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
@@ -1090,14 +1097,14 @@ debounce-fn@^4.0.0:
|
||||
dependencies:
|
||||
mimic-fn "^3.0.0"
|
||||
|
||||
debug@4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3:
|
||||
debug@4, debug@^4.3.3:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.4:
|
||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
|
||||
integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
|
||||
@@ -1313,9 +1320,9 @@ electron-updater@^6.2:
|
||||
tiny-typed-emitter "^2.1.0"
|
||||
|
||||
electron@^30:
|
||||
version "30.0.9"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-30.0.9.tgz#b11400e4642a4b635e79244ba365f1d401ee60b5"
|
||||
integrity sha512-ArxgdGHVu3o5uaP+Tqj8cJDvU03R6vrGrOqiMs7JXLnvQHMqXJIIxmFKQAIdJW8VoT3ac3hD21tA7cPO10RLow==
|
||||
version "30.1.2"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-30.1.2.tgz#9c8b9b0d0e3f07783d8c5dbd9519b3ffd11f1551"
|
||||
integrity sha512-A5CFGwbA+HSXnzwjc8fP2GIezBcAb0uN/VbNGLOW8DHOYn07rvJ/1bAJECHUUzt5zbfohveG3hpMQiYpbktuDw==
|
||||
dependencies:
|
||||
"@electron/get" "^2.0.0"
|
||||
"@types/node" "^20.9.0"
|
||||
@@ -1395,16 +1402,16 @@ eslint-visitor-keys@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb"
|
||||
integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==
|
||||
|
||||
eslint@^9.4.0:
|
||||
version "9.4.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.4.0.tgz#79150c3610ae606eb131f1d648d5f43b3d45f3cd"
|
||||
integrity sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==
|
||||
eslint@^9:
|
||||
version "9.6.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.6.0.tgz#9f54373afa15e1ba356656a8d96233182027fb49"
|
||||
integrity sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.6.1"
|
||||
"@eslint/config-array" "^0.15.1"
|
||||
"@eslint/config-array" "^0.17.0"
|
||||
"@eslint/eslintrc" "^3.1.0"
|
||||
"@eslint/js" "9.4.0"
|
||||
"@eslint/js" "9.6.0"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@humanwhocodes/retry" "^0.3.0"
|
||||
"@nodelib/fs.walk" "^1.2.8"
|
||||
@@ -1415,8 +1422,8 @@ eslint@^9.4.0:
|
||||
escape-string-regexp "^4.0.0"
|
||||
eslint-scope "^8.0.1"
|
||||
eslint-visitor-keys "^4.0.0"
|
||||
espree "^10.0.1"
|
||||
esquery "^1.4.2"
|
||||
espree "^10.1.0"
|
||||
esquery "^1.5.0"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
file-entry-cache "^8.0.0"
|
||||
@@ -1435,16 +1442,16 @@ eslint@^9.4.0:
|
||||
strip-ansi "^6.0.1"
|
||||
text-table "^0.2.0"
|
||||
|
||||
espree@^10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-10.0.1.tgz#600e60404157412751ba4a6f3a2ee1a42433139f"
|
||||
integrity sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==
|
||||
espree@^10.0.1, espree@^10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56"
|
||||
integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==
|
||||
dependencies:
|
||||
acorn "^8.11.3"
|
||||
acorn "^8.12.0"
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^4.0.0"
|
||||
|
||||
esquery@^1.4.2:
|
||||
esquery@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
|
||||
integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
|
||||
@@ -1893,11 +1900,6 @@ hosted-git-info@^4.1.0:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
html-entities@^2.5:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f"
|
||||
integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==
|
||||
|
||||
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
||||
@@ -2123,11 +2125,6 @@ jake@^10.8.5:
|
||||
filelist "^1.0.4"
|
||||
minimatch "^3.1.2"
|
||||
|
||||
jpeg-js@^0.4:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa"
|
||||
integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
@@ -2259,6 +2256,11 @@ lowercase-keys@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
|
||||
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
|
||||
|
||||
lru-cache@^10.2:
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.3.0.tgz#4a4aaf10c84658ab70f79a85a9a3f1e1fb11196b"
|
||||
integrity sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==
|
||||
|
||||
lru-cache@^10.2.0:
|
||||
version "10.2.2"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
|
||||
@@ -2762,9 +2764,9 @@ prettier-plugin-packagejson@^2:
|
||||
synckit "0.9.0"
|
||||
|
||||
prettier@^3:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.0.tgz#d173ea0524a691d4c0b1181752f2b46724328cdf"
|
||||
integrity sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.2.tgz#03ff86dc7c835f2d2559ee76876a3914cec4a90a"
|
||||
integrity sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==
|
||||
|
||||
progress@^2.0.3:
|
||||
version "2.0.3"
|
||||
@@ -3329,16 +3331,21 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||
|
||||
typescript-eslint@8.0.0-alpha.10:
|
||||
version "8.0.0-alpha.10"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.0.0-alpha.10.tgz#2172d41ab30c8447927c3823c5a549b9c09be89f"
|
||||
integrity sha512-iMbN7boDtUmcSDor/J022+H4G018W3r3RSUUr7yoghMTmFuKVIkI89xJHDg82DBGYkA0xOoDNPBr7XfRFbEXKQ==
|
||||
typescript-eslint@^8.0.0-alpha.39:
|
||||
version "8.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.0.0-alpha.39.tgz#6b5eac89a47b2f6fed449cf45502d2c5e4909745"
|
||||
integrity sha512-bsuR1BVJfHr7sBh7Cca962VPIcP+5UWaIa/+6PpnFZ+qtASjGTxKWIF5dG2o73BX9NsyqQfvRWujb3M9CIoRXA==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/parser" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.10"
|
||||
"@typescript-eslint/eslint-plugin" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/parser" "8.0.0-alpha.39"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.39"
|
||||
|
||||
typescript@^5, typescript@^5.3.3, typescript@^5.4.3:
|
||||
typescript@^5:
|
||||
version "5.5.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa"
|
||||
integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==
|
||||
|
||||
typescript@^5.3.3, typescript@^5.4.3:
|
||||
version "5.4.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611"
|
||||
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
|
||||
|
||||
@@ -1,73 +1,77 @@
|
||||
---
|
||||
title: Security and privacy FAQ
|
||||
description:
|
||||
Frequently asked questions about security and privacy of Ente Photos
|
||||
title: Security and Privacy FAQ
|
||||
description: Comprehensive information about security and privacy measures in Ente Photos
|
||||
---
|
||||
|
||||
# Security and privacy
|
||||
# Security and Privacy FAQ
|
||||
|
||||
## Can Ente see my photos and videos?
|
||||
Welcome to Ente Photos' Security and Privacy FAQ. This document provides
|
||||
detailed information about our security practices, privacy measures, and how we
|
||||
protect your data. We are committed to maintaining the highest standards of data
|
||||
protection and transparency.
|
||||
|
||||
No.
|
||||
## Data Encryption and Storage
|
||||
|
||||
Your files are encrypted with a key before they are uploaded to our servers.
|
||||
### Can Ente see my photos and videos?
|
||||
No. Your files are encrypted on your device before being uploaded to our
|
||||
servers. The encryption keys are derived from your password using advanced key
|
||||
derivation functions. Since only you know your password, only you can decrypt
|
||||
your files. For technical details, please see our [architecture
|
||||
document](https://ente.io/architecture).
|
||||
|
||||
These keys can be accessed only with your password.
|
||||
### How is my data encrypted?
|
||||
We use the following encryption algorithms:
|
||||
- Encryption: `XChaCha20` and `XSalsa20`
|
||||
- Authentication: Poly1305 message authentication code (MAC)
|
||||
- Key derivation: Argon2id with high memory and computation parameters
|
||||
|
||||
Since only you know your password, only you can decrypt your files.
|
||||
These algorithms are implemented using
|
||||
[libsodium](https://libsodium.gitbook.io/doc/), a externally audited
|
||||
cryptographic library. Our [architecture document](https://ente.io/architecture)
|
||||
provides full technical specifications.
|
||||
|
||||
To learn more about our encryption protocol, please read about our
|
||||
[architecture](https://ente.io/architecture).
|
||||
### Where is my data stored?
|
||||
Your encrypted data is stored redundantly across multiple providers in the EU:
|
||||
- Amsterdam, Netherlands
|
||||
- Paris, France
|
||||
- Frankfurt, Germany
|
||||
|
||||
## How is my data encrypted?
|
||||
We use a combination of object storage and distributed databases to ensure high
|
||||
availability and durability. Our [reliability
|
||||
document](https://ente.io/reliability) provides in-depth information about our
|
||||
storage infrastructure and data replication strategies.
|
||||
|
||||
We use [libsodium](https://libsodium.gitbook.io/doc/)'s implementations
|
||||
`XChaCha20` and `XSalsa20` to encrypt your data, along with `Poly1305` MAC for
|
||||
authentication.
|
||||
### How does Ente's encryption compare to industry standards?
|
||||
Our encryption model goes beyond industry standards. While many services use
|
||||
server-side encryption, we implement end-to-end encryption. This means that even
|
||||
in the unlikely event of a server breach, your data remains protected.
|
||||
|
||||
Please refer to the document on our [architecture](https://ente.io/architecture)
|
||||
for more details.
|
||||
## Account Security
|
||||
|
||||
## Where is my data stored?
|
||||
### What happens if I forget my password?
|
||||
You can reset your password using your recovery key. This key is a randomly
|
||||
generated string provided to you during account creation. Store it securely, as
|
||||
it's your lifeline if you forget your password. If you lose both your password
|
||||
and recovery key, we cannot recover your account or data due to our
|
||||
zero-knowledge architecture.
|
||||
|
||||
Your data is replicated to multiple providers in different countries in the EU.
|
||||
|
||||
Currently we have datacenters in the following locations:
|
||||
|
||||
- Amsterdam, Netherlands
|
||||
- Paris, France
|
||||
- Frankfurt, Germany
|
||||
|
||||
Much more details about our replication and reliability are documented
|
||||
[here](https://ente.io/reliability).
|
||||
|
||||
## What happens if I forget my password?
|
||||
|
||||
You can reset your password with your recovery key.
|
||||
|
||||
If you lose both your password and your recovery key, you will not be able to
|
||||
decrypt your data.
|
||||
|
||||
## Can I change my password?
|
||||
|
||||
Yes.
|
||||
|
||||
You can change your password from any of our apps.
|
||||
|
||||
Thanks to our [architecture](https://ente.io/architecture), you can do so
|
||||
without having to re-encrypt any of your files.
|
||||
### Can I change my password?
|
||||
Yes, you can change your password at any time from our apps. Our architecture
|
||||
allows password changes without re-encrypting your entire library.
|
||||
|
||||
The privacy of your account is a function of the strength of your password,
|
||||
please choose a strong one.
|
||||
|
||||
## Do you support 2FA?
|
||||
### Do you support two-factor authentication (2FA)?
|
||||
Yes, we recommend enabling 2FA for an additional layer of security. We support:
|
||||
- Time-based One-Time Passwords (TOTP)
|
||||
- WebAuthn/FIDO2 for hardware security keys
|
||||
|
||||
Yes.
|
||||
You can set up 2FA in the settings of our mobile or desktop apps.
|
||||
|
||||
You can setup two-factor authentication from the settings screen of the mobile
|
||||
app or from the side bar of our desktop app.
|
||||
## Sharing and Collaboration
|
||||
|
||||
## How does sharing work?
|
||||
### How does sharing work?
|
||||
|
||||
The information required to decrypt an album is encrypted with the recipient's
|
||||
public key such that only they can decrypt them.
|
||||
@@ -81,22 +85,31 @@ and is never sent to our servers.
|
||||
Please note that only users on the paid plan are allowed to share albums. The
|
||||
receiver just needs a free Ente account.
|
||||
|
||||
## Has the Ente Photos app been audited by a credible source?
|
||||
## Security Audits
|
||||
|
||||
## Has the Ente Photos app been audited by a credible source?
|
||||
Yes, Ente Photos has undergone a thorough security audit conducted by Cure53, in
|
||||
collaboration with Symbolic Software. Cure53 is a prominent German cybersecurity
|
||||
firm, while Symbolic Software specializes in applied cryptography. Please find
|
||||
the full report here: https://ente.io/blog/cryptography-audit/
|
||||
|
||||
## How can I delete my account?
|
||||
## Account Management
|
||||
|
||||
### How can I delete my account?
|
||||
|
||||
You can delete your account at any time by using the "Delete account" option in
|
||||
the settings. For security reasons, we request you to delete your account on
|
||||
your own instead of contacting support to ask them to delete your account.
|
||||
|
||||
Note that both Ente photos and Ente auth data will be deleted when you delete
|
||||
Note that both Ente Photos and Ente Auth data will be deleted when you delete
|
||||
your account (irrespective of which app you delete it from) since both photos
|
||||
and auth use the same underlying account.
|
||||
|
||||
To know details of how your data is deleted, including when you delete your
|
||||
account, please see https://ente.io/blog/how-ente-deletes-data/.
|
||||
|
||||
## Additional Support
|
||||
|
||||
For any security or privacy questions not covered here, please contact our team
|
||||
at security@ente.io. We're committed to addressing your concerns and
|
||||
continuously improving our security measures.
|
||||
|
||||
@@ -5,41 +5,41 @@ description: How to report bugs and share the logs from your Ente Photos app
|
||||
|
||||
# Sharing debug logs
|
||||
|
||||
In some cases when you report a bug, our customer support might request you to
|
||||
share debug logs from your app to help our developers find the issue.
|
||||
In some cases when you report an issue, our customer support might request you
|
||||
to share debug logs from your app to help our developers find the issue.
|
||||
|
||||
Note that the debug logs contain potentially sensitive information like the file
|
||||
names, so please feel free to not share them if you have any hesitation or want
|
||||
to keep these private. We will try to diagnose the issue even without the logs,
|
||||
the logs just make the process a bit faster and easier.
|
||||
|
||||
### Mobile
|
||||
## Mobile
|
||||
|
||||
To **_Report a bug_** on your mobile device, follow these steps:
|
||||
- Open settings (tap on the three horizontal lines button).
|
||||
- Tap on _Support_ from the settings.
|
||||
- Select for the option to _Report a Bug_.
|
||||
- Tap on _Report a bug_.
|
||||
|
||||
- Tap on the three horizontal lines to access the settings.
|
||||
- Tap on **"Support"** from the settings.
|
||||
- Select for the option to **"Report a Bug"**.
|
||||
- Tap on **"Report a bug"** .
|
||||
## Desktop
|
||||
|
||||
### Desktop
|
||||
- Click on _Help_ menu at the top of your screen, and select the _View logs_
|
||||
option.
|
||||
- Open settings (click on the three horizontal lines button located at the top
|
||||
left corner of the screen).
|
||||
- Click on _Support_. This will open your email client where you can attach
|
||||
the logs in the email and describe the issue.
|
||||
|
||||
To **_Report a bug_** on the desktop app, follow these steps:
|
||||
## Web
|
||||
|
||||
- Click on the three horizontal lines located in the top left corner of the
|
||||
screen to access the settings.
|
||||
- Click on **"Debug logs"** from the settings.
|
||||
- Click on **Download logs**.
|
||||
- Then Click on **"Support"**.
|
||||
- Attach the downloaded logs in the email and describe the issue.
|
||||
- Open settings (click on the three horizontal lines button located at the top
|
||||
left corner of the screen).
|
||||
- Click on _Debug Logs_ towards the bottom of settings.
|
||||
- Click on _Download logs_
|
||||
- Click on _Support_. This will open your email client where you can attach
|
||||
the logs in the email and describe the issue.
|
||||
|
||||
### Web
|
||||
## Send email manually
|
||||
|
||||
To **_Report a bug_** on the web, follow these steps:
|
||||
|
||||
- Click on the three horizontal lines located in the top left corner of the
|
||||
screen to access the settings.
|
||||
- Click on **"Debug Logs"**
|
||||
- Click on **Download logs**
|
||||
- Click on **"Support"** from the settings.
|
||||
- Attach the downloaded logs in the email and describe the issue.
|
||||
If _Report a bug_ or _Support_ doesn't automatically open your email client, you
|
||||
can also directly send a mail to <a
|
||||
href="mailto:support@ente.io">support@ente.io</a>.
|
||||
|
||||
@@ -8,7 +8,7 @@ description: Using a custom self-hosted server with Ente client apps and CLI
|
||||
You can modify various Ente client apps and CLI to connect to a self hosted
|
||||
custom server endpoint.
|
||||
|
||||
## Mobile apps
|
||||
## Mobile
|
||||
|
||||
The pre-built Ente apps from GitHub / App Store / Play Store / F-Droid can be
|
||||
easily configured to use a custom server.
|
||||
@@ -18,6 +18,52 @@ configure the endpoint the app should be connecting to.
|
||||
|
||||

|
||||
|
||||
## Desktop and web
|
||||
|
||||
Same as the mobile app, you can tap 7 times on the onboarding screen to
|
||||
configure the endpoint the app should connect to.
|
||||
|
||||
<div align="center">
|
||||
|
||||
{width=400px}
|
||||
|
||||
</div>
|
||||
|
||||
This works on both the desktop app and web app (if you deploy on your own).
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> This setting is currently available in the nightly builds of the desktop app.
|
||||
> It'll be available in the regular builds with the upcoming release (1.7.2).
|
||||
|
||||
To make it easier to identify when a custom server is being used, app will
|
||||
thereafter show the endpoint in use (if not Ente's production server) at the
|
||||
bottom of the login prompt:
|
||||
|
||||

|
||||
|
||||
Similarly, it'll be shown at other screens during the login flow. After login,
|
||||
you can also see it at the bottom of the sidebar.
|
||||
|
||||
Note that the custom server configured this way is cleared when you reset the
|
||||
state during logout. In particular, the app also does a reset when you press the
|
||||
change email button during the login flow.
|
||||
|
||||
### Building from source
|
||||
|
||||
Alternatively (e.g. if you don't wish to configure this setting and just want to
|
||||
change the endpoint the client connects to by default), you can build the app
|
||||
from source and use the `NEXT_PUBLIC_ENTE_ENDPOINT` environment variable to tell
|
||||
it which server to connect to. For example:
|
||||
|
||||
```sh
|
||||
NEXT_PUBLIC_ENTE_ENDPOINT=http://localhost:8080 yarn dev:photos
|
||||
```
|
||||
|
||||
For more details, see
|
||||
[hosting the web app](https://help.ente.io/self-hosting/guides/web-app).
|
||||
|
||||
## CLI
|
||||
|
||||
> [!NOTE]
|
||||
@@ -36,16 +82,3 @@ endpoint:
|
||||
|
||||
(Another
|
||||
[example](https://github.com/ente-io/ente/blob/main/cli/config.yaml.example))
|
||||
|
||||
## Web apps and Photos desktop app
|
||||
|
||||
You will need to build the app from source and use the
|
||||
`NEXT_PUBLIC_ENTE_ENDPOINT` environment variable to tell it which server to
|
||||
connect to. For example:
|
||||
|
||||
```sh
|
||||
NEXT_PUBLIC_ENTE_ENDPOINT=http://localhost:8080 yarn dev:photos
|
||||
```
|
||||
|
||||
For more details, see
|
||||
[hosting the web app](https://help.ente.io/self-hosting/guides/web-app).
|
||||
|
||||
|
After Width: | Height: | Size: 231 KiB |
BIN
docs/docs/self-hosting/guides/custom-server/web-dev-settings.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
@@ -659,9 +659,9 @@ preact@^10.0.0:
|
||||
integrity sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==
|
||||
|
||||
prettier@^3:
|
||||
version "3.2.5"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
|
||||
integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.2.tgz#03ff86dc7c835f2d2559ee76876a3914cec4a90a"
|
||||
integrity sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==
|
||||
|
||||
rfdc@^1.3.1:
|
||||
version "1.3.1"
|
||||
|
||||
@@ -17,7 +17,7 @@ RUN \
|
||||
# Install SCW CLI
|
||||
# Latest release: https://github.com/scaleway/scaleway-cli/releases/latest
|
||||
RUN \
|
||||
export VERSION="2.26.0" && \
|
||||
export VERSION="2.32.1" && \
|
||||
curl -o /usr/local/bin/scw -L "https://github.com/scaleway/scaleway-cli/releases/download/v${VERSION}/scaleway-cli_${VERSION}_linux_amd64" && \
|
||||
chmod +x /usr/local/bin/scw
|
||||
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
|
||||
# Find the name of the latest backup
|
||||
# The backup file name contains the epoch, so we can just sort.
|
||||
BACKUP_FILE=$(rclone lsf --include 'db-*.custom' --files-only $RCLONE_DESTINATION | sort | tail -1)
|
||||
if test -z "$1"; then
|
||||
# Find the name of the latest backup.
|
||||
#
|
||||
# The backup file name contains the epoch, so we can just sort.
|
||||
BACKUP_FILE=$(rclone lsf --include 'db-*.custom' --files-only $RCLONE_DESTINATION | sort | tail -1)
|
||||
else
|
||||
# If a CLI argument is provided, use that as the name of the backup file to
|
||||
# restore.
|
||||
BACKUP_FILE="$1"
|
||||
fi
|
||||
|
||||
# Download it
|
||||
rclone copy --log-level INFO "${RCLONE_DESTINATION}${BACKUP_FILE}" .
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
# https://prometheus.io/docs/prometheus/latest/configuration/
|
||||
|
||||
global:
|
||||
scrape_interval: 30s # Default is 1m
|
||||
|
||||
scrape_configs:
|
||||
- job_name: museum
|
||||
static_configs:
|
||||
|
||||
@@ -11,12 +11,15 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"date-fns": "^3.6.0",
|
||||
"react": "^18",
|
||||
"react-datepicker": "^7.1.0",
|
||||
"react-dom": "^18",
|
||||
"react-toastify": "^10.0.5",
|
||||
"zod": "^3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^7",
|
||||
@@ -29,7 +32,7 @@
|
||||
"prettier": "^3",
|
||||
"prettier-plugin-organize-imports": "^3.2",
|
||||
"prettier-plugin-packagejson": "^2.5",
|
||||
"typescript": "^5.4.5",
|
||||
"typescript": "^5",
|
||||
"vite": "^5.2"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
|
||||
@@ -19,6 +19,20 @@
|
||||
border-radius: 5px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
#submitbtn {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #009879;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#submitbtn:hover {
|
||||
background-color: #007c6c;
|
||||
}
|
||||
|
||||
.fetch-button-container button:hover {
|
||||
background-color: #007c6c;
|
||||
@@ -122,3 +136,321 @@ button {
|
||||
.dropdown-menu button:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.modal-header .close-btn {
|
||||
cursor: pointer;
|
||||
color: #777;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Styles for draggable modal */
|
||||
.modal.draggable {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.modal.draggable .modal-header {
|
||||
cursor: move;
|
||||
}
|
||||
.popup {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: lightgreen;
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.popup-content div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:root {
|
||||
--popup-bg-color-light: #fff;
|
||||
--popup-bg-color-dark: #2c2c2c;
|
||||
--popup-border-color-light: #ccc;
|
||||
--popup-border-color-dark: #444;
|
||||
--popup-text-color-light: #000;
|
||||
--popup-text-color-dark: #fff;
|
||||
--popup-shadow-light: rgba(0, 0, 0, 0.1);
|
||||
--popup-shadow-dark: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.update-subscription-popup {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 400px;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: var(--popup-bg-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
padding: 20px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0px 0px 10px var(--popup-shadow-light);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
align-self: flex-end;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
color: var(--popup-text-color-light);
|
||||
}
|
||||
|
||||
.popup-content h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.popup-content form label {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.popup-content form input,
|
||||
.popup-content form select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-top: 5px;
|
||||
background-color: var(--popup-bg-color-light);
|
||||
color: var(--popup-text-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
}
|
||||
|
||||
.popup-content form button {
|
||||
padding: 10px 15px;
|
||||
margin-top: 10px;
|
||||
cursor: pointer;
|
||||
background-color: var(--popup-bg-color-light);
|
||||
color: var(--popup-text-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-select select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
background-color: var(--popup-bg-color-light);
|
||||
color: var(--popup-text-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.custom-select::after {
|
||||
content: "\25BC";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.update-subscription-popup {
|
||||
background-color: var(--popup-bg-color-dark);
|
||||
border-color: var(--popup-border-color-dark);
|
||||
color: var(--popup-text-color-dark);
|
||||
box-shadow: 0px 0px 10px var(--popup-shadow-dark);
|
||||
}
|
||||
|
||||
.close-button {
|
||||
color: var(--popup-text-color-dark);
|
||||
}
|
||||
|
||||
.popup-content form input,
|
||||
.popup-content form select {
|
||||
background-color: var(--popup-bg-color-dark);
|
||||
color: var(--popup-text-color-dark);
|
||||
border: 1px solid var(--popup-border-color-dark);
|
||||
}
|
||||
|
||||
.popup-content form button {
|
||||
background-color: var(--popup-bg-color-dark);
|
||||
color: var(--popup-text-color-dark);
|
||||
border: 1px solid var(--popup-border-color-dark);
|
||||
}
|
||||
}
|
||||
:root {
|
||||
--popup-bg-color-light: #fff;
|
||||
--popup-bg-color-dark: #2c2c2c;
|
||||
--popup-border-color-light: #ccc;
|
||||
--popup-border-color-dark: #444;
|
||||
--popup-text-color-light: #000;
|
||||
--popup-text-color-dark: #fff;
|
||||
--popup-shadow-light: rgba(0, 0, 0, 0.1);
|
||||
--popup-shadow-dark: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.update-subscription-popup {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: var(--popup-bg-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
padding: 20px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0px 0px 10px var(--popup-shadow-light);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
align-self: flex-end;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
color: var(--popup-text-color-light);
|
||||
}
|
||||
|
||||
.popup-content h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
background-color: var(--popup-bg-color-light);
|
||||
color: var(--popup-text-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
border-radius: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-select select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
background-color: var(--popup-bg-color-light);
|
||||
color: var(--popup-text-color-light);
|
||||
border: 1px solid var(--popup-border-color-light);
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.custom-select::after {
|
||||
content: "\25BC";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.update-subscription-popup {
|
||||
background-color: var(--popup-bg-color-dark);
|
||||
border-color: var(--popup-border-color-dark);
|
||||
color: var(--popup-text-color-dark);
|
||||
box-shadow: 0px 0px 10px var(--popup-shadow-dark);
|
||||
}
|
||||
|
||||
.close-button {
|
||||
color: var(--popup-text-color-dark);
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
background-color: var(--popup-bg-color-dark);
|
||||
color: var(--popup-text-color-dark);
|
||||
border: 1px solid var(--popup-border-color-dark);
|
||||
}
|
||||
|
||||
.form-group button {
|
||||
background-color: var(--popup-bg-color-dark);
|
||||
color: var(--popup-text-color-dark);
|
||||
border: 1px solid var(--popup-border-color-dark);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export const App: React.FC = () => {
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [userData, setUserData] = useState<UserData | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isDataFetched, setIsDataFetched] = useState<boolean>(false); // Track if data has been fetched successfully
|
||||
const [isDataFetched, setIsDataFetched] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const storedToken = localStorage.getItem("token");
|
||||
@@ -46,11 +46,11 @@ export const App: React.FC = () => {
|
||||
console.log("API Response:", userDataResponse);
|
||||
setUserData(userDataResponse);
|
||||
setError(null);
|
||||
setIsDataFetched(true); // Set to true when data is successfully fetched
|
||||
setIsDataFetched(true);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
setError((error as Error).message);
|
||||
setIsDataFetched(false); // Set to false if there's an error fetching data
|
||||
setIsDataFetched(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ export const App: React.FC = () => {
|
||||
displayValue = value;
|
||||
}
|
||||
} else if (typeof value === "object" && value !== null) {
|
||||
displayValue = JSON.stringify(value, null, 2); // Pretty print JSON
|
||||
displayValue = JSON.stringify(value, null, 2);
|
||||
} else if (value === null) {
|
||||
displayValue = "null";
|
||||
} else if (
|
||||
@@ -124,7 +124,7 @@ export const App: React.FC = () => {
|
||||
} else if (typeof value === "undefined") {
|
||||
displayValue = "undefined";
|
||||
} else {
|
||||
displayValue = value as string; // Fallback for any other types
|
||||
displayValue = value as string;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -157,7 +157,7 @@ export const App: React.FC = () => {
|
||||
|
||||
const handleKeyPress = (event: React.KeyboardEvent<HTMLFormElement>) => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault(); // Prevent form submission
|
||||
event.preventDefault();
|
||||
fetchData().catch((error: unknown) =>
|
||||
console.error("Fetch data error:", error),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import "../App.css";
|
||||
import { apiOrigin } from "../services/support";
|
||||
import UpdateSubscription from "./UpdateSubscription"; // Import the UpdateSubscription component
|
||||
|
||||
interface SidebarProps {
|
||||
token: string;
|
||||
@@ -12,18 +13,36 @@ interface UserData {
|
||||
ID: string;
|
||||
};
|
||||
}
|
||||
interface ActionResponse {
|
||||
success?: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
const [, /*userId*/ setUserId] = useState<string | null>(null);
|
||||
const [userId, setUserId] = useState<string | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [message, setMessage] = useState<string | null>(null);
|
||||
const [dropdownVisible, setDropdownVisible] = useState<boolean>(false);
|
||||
const [showUpdateSubscription, setShowUpdateSubscription] =
|
||||
useState<boolean>(false); // State to control UpdateSubscription popup
|
||||
|
||||
interface ApiResponse {
|
||||
data: {
|
||||
userId: string;
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setDropdownVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async (): Promise<string | null> => {
|
||||
if (!email || !token) {
|
||||
@@ -32,9 +51,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `${apiOrigin}/admin/user?email=${encodeURIComponent(
|
||||
email,
|
||||
)}&token=${encodeURIComponent(token)}`;
|
||||
const url = `${apiOrigin}/admin/user?email=${encodeURIComponent(email)}&token=${encodeURIComponent(token)}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
@@ -70,9 +87,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
Closefamily: "/admin/user/close-family",
|
||||
};
|
||||
|
||||
const url = `${apiOrigin}${actionUrls[action]}?id=${encodeURIComponent(
|
||||
userId,
|
||||
)}&token=${encodeURIComponent(token)}`;
|
||||
const url = `${apiOrigin}${actionUrls[action]}?id=${encodeURIComponent(userId)}&token=${encodeURIComponent(token)}`;
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -85,7 +100,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const result = (await response.json()) as ApiResponse;
|
||||
const result = (await response.json()) as ActionResponse;
|
||||
console.log("API Response:", result);
|
||||
|
||||
setMessage(`${action} completed successfully`);
|
||||
@@ -109,8 +124,55 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const deleteUser = async () => {
|
||||
try {
|
||||
const url = `${apiOrigin}/admin/user/delete?email=${encodeURIComponent(email)}&token=${encodeURIComponent(token)}`;
|
||||
const response = await fetch(url, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Network response was not ok: ${response.status}`,
|
||||
);
|
||||
}
|
||||
|
||||
setMessage("Delete Account completed successfully");
|
||||
setError(null);
|
||||
setTimeout(() => {
|
||||
setMessage(null);
|
||||
}, 1000);
|
||||
setDropdownVisible(false);
|
||||
} catch (error) {
|
||||
console.error(`Error deleting account:`, error);
|
||||
setError(
|
||||
error instanceof Error && typeof error.message === "string"
|
||||
? error.message
|
||||
: "An unexpected error occurred",
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
setError(null);
|
||||
}, 1000);
|
||||
setMessage(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleActionClick = async (action: string) => {
|
||||
try {
|
||||
if (action === "UpdateSubscription") {
|
||||
const fetchedUserId = await fetchData();
|
||||
if (fetchedUserId) {
|
||||
setShowUpdateSubscription(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === "DeleteAccount") {
|
||||
await deleteUser();
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchedUserId = await fetchData();
|
||||
if (!fetchedUserId) {
|
||||
throw new Error("Incorrect email id or token");
|
||||
@@ -140,6 +202,8 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
{ value: "Disable2FA", label: "Disable 2FA" },
|
||||
{ value: "Closefamily", label: "Close Family" },
|
||||
{ value: "DisablePasskeys", label: "Disable Passkeys" },
|
||||
{ value: "DeleteAccount", label: "Delete Account" },
|
||||
{ value: "UpdateSubscription", label: "Update Subscription" }, // New option added here
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -149,7 +213,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
MORE
|
||||
</button>
|
||||
{dropdownVisible && (
|
||||
<div className="dropdown-menu">
|
||||
<div className="dropdown-menu" ref={dropdownRef}>
|
||||
<ul>
|
||||
{dropdownOptions.map((option) => (
|
||||
<li key={option.value}>
|
||||
@@ -178,6 +242,13 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
|
||||
{error ? `Error: ${error}` : `Success: ${message}`}
|
||||
</div>
|
||||
)}
|
||||
{showUpdateSubscription && userId && (
|
||||
<UpdateSubscription
|
||||
token={token}
|
||||
userId={userId}
|
||||
onClose={() => setShowUpdateSubscription(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
179
infra/staff/src/components/UpdateSubscription.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import DatePicker from "react-datepicker";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import "../App.css";
|
||||
import { apiOrigin } from "../services/support";
|
||||
interface UpdateSubscriptionProps {
|
||||
token: string;
|
||||
userId: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const UpdateSubscription: React.FC<UpdateSubscriptionProps> = ({
|
||||
token,
|
||||
userId,
|
||||
onClose,
|
||||
}) => {
|
||||
const [expiryTime, setExpiryTime] = useState<Date | null>(null);
|
||||
const [productId, setProductId] = useState<string>("50gb_monthly");
|
||||
const [paymentProvider, setPaymentProvider] = useState<string>("bitpay");
|
||||
const [transactionId, setTransactionId] = useState<string>("");
|
||||
const [message, setMessage] = useState<string | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [storage, setStorage] = useState<number | "">("");
|
||||
|
||||
useEffect(() => {
|
||||
if (productId === "50gb_yearly" || productId === "50gb_monthly") {
|
||||
setStorage(50 * 1024 * 1024 * 1024);
|
||||
} else if (
|
||||
productId === "200gb_yearly" ||
|
||||
productId === "200gb_monthly"
|
||||
) {
|
||||
setStorage(200 * 1024 * 1024 * 1024);
|
||||
} else if (
|
||||
productId === "500gb_yearly" ||
|
||||
productId === "500gb_monthly"
|
||||
) {
|
||||
setStorage(500 * 1024 * 1024 * 1024);
|
||||
} else if (
|
||||
productId === "2000gb_yearly" ||
|
||||
productId === "2000gb_monthly"
|
||||
) {
|
||||
setStorage(2000 * 1024 * 1024 * 1024);
|
||||
} else {
|
||||
setStorage("");
|
||||
}
|
||||
}, [productId]);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
const expiryTimeTimestamp = expiryTime
|
||||
? expiryTime.getTime() * 1000
|
||||
: "";
|
||||
|
||||
const url = `${apiOrigin}/admin/user/subscription`;
|
||||
const body = {
|
||||
userId,
|
||||
storage,
|
||||
expiryTime: expiryTimeTimestamp,
|
||||
productId,
|
||||
paymentProvider,
|
||||
transactionId,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-AUTH-TOKEN": token,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Network response was not ok: ${response.status}`,
|
||||
);
|
||||
}
|
||||
|
||||
setMessage("Subscription updated successfully");
|
||||
setError(null);
|
||||
setTimeout(() => {
|
||||
setMessage(null);
|
||||
onClose();
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
console.error("Error updating subscription:", error);
|
||||
setError(
|
||||
error instanceof Error && typeof error.message === "string"
|
||||
? error.message
|
||||
: "An unexpected error occurred",
|
||||
);
|
||||
setTimeout(() => {
|
||||
setError(null);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmitWrapper = (event: React.FormEvent) => {
|
||||
handleSubmit(event).catch((error: unknown) => {
|
||||
console.error("Error in handleSubmit:", error);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="update-subscription-popup">
|
||||
<div className="popup-content">
|
||||
<button className="close-button" onClick={onClose}>
|
||||
X
|
||||
</button>
|
||||
<h2>Update Subscription</h2>
|
||||
<form onSubmit={handleSubmitWrapper}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="expiry-time">Expiry Time:</label>
|
||||
<DatePicker
|
||||
id="expiry-time"
|
||||
selected={expiryTime}
|
||||
onChange={(date) => setExpiryTime(date)}
|
||||
dateFormat="dd/MM/yyyy"
|
||||
showYearDropdown
|
||||
scrollableYearDropdown
|
||||
yearDropdownItemNumber={15}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="product-id">Choose Your Plan:</label>
|
||||
<select
|
||||
id="product-id"
|
||||
value={productId}
|
||||
onChange={(e) => setProductId(e.target.value)}
|
||||
>
|
||||
<option value="50gb_monthly">50GB/Month</option>
|
||||
<option value="50gb_yearly">50GB/Year</option>
|
||||
<option value="200gb_monthly">200GB/Month</option>
|
||||
<option value="200gb_yearly">200GB/Year</option>
|
||||
<option value="500gb_monthly">500GB/Month</option>
|
||||
<option value="500gb_yearly">500GB/Year</option>
|
||||
<option value="2000gb_monthly">2000GB/Month</option>
|
||||
<option value="2000gb_yearly">2000GB/Year</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="payment-provider">
|
||||
Payment Provider:
|
||||
</label>
|
||||
<select
|
||||
id="payment-provider"
|
||||
value={paymentProvider}
|
||||
onChange={(e) => setPaymentProvider(e.target.value)}
|
||||
>
|
||||
<option value="bitpay">BitPay</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="transaction-id">Transaction ID:</label>
|
||||
<input
|
||||
id="transaction-id"
|
||||
type="text"
|
||||
value={transactionId}
|
||||
onChange={(e) => setTransactionId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" id="submitbtn">
|
||||
Update
|
||||
</button>
|
||||
</form>
|
||||
{(error ?? message) && (
|
||||
<div className={`message ${error ? "error" : "success"}`}>
|
||||
{error ? `Error: ${error}` : `Success: ${message}`}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateSubscription;
|
||||
@@ -23,7 +23,7 @@
|
||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz"
|
||||
integrity sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==
|
||||
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.24.5":
|
||||
"@babel/core@^7.24.5":
|
||||
version "7.24.6"
|
||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz"
|
||||
integrity sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==
|
||||
@@ -208,11 +208,121 @@
|
||||
"@babel/helper-validator-identifier" "^7.24.6"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@esbuild/aix-ppc64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
|
||||
integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
|
||||
|
||||
"@esbuild/android-arm64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
|
||||
integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
|
||||
|
||||
"@esbuild/android-arm@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
|
||||
integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
|
||||
|
||||
"@esbuild/android-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
|
||||
integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
|
||||
|
||||
"@esbuild/darwin-arm64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
|
||||
integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
|
||||
|
||||
"@esbuild/darwin-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz"
|
||||
integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
|
||||
integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
|
||||
|
||||
"@esbuild/freebsd-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
|
||||
integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
|
||||
|
||||
"@esbuild/linux-arm64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
|
||||
integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
|
||||
|
||||
"@esbuild/linux-arm@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
|
||||
integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
|
||||
|
||||
"@esbuild/linux-ia32@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
|
||||
integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
|
||||
|
||||
"@esbuild/linux-loong64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
|
||||
integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
|
||||
|
||||
"@esbuild/linux-mips64el@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
|
||||
integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
|
||||
|
||||
"@esbuild/linux-ppc64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
|
||||
integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
|
||||
|
||||
"@esbuild/linux-riscv64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
|
||||
integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
|
||||
|
||||
"@esbuild/linux-s390x@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
|
||||
integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
|
||||
|
||||
"@esbuild/linux-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
|
||||
integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
|
||||
|
||||
"@esbuild/netbsd-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
|
||||
integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
|
||||
|
||||
"@esbuild/openbsd-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
|
||||
integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
|
||||
|
||||
"@esbuild/sunos-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
|
||||
integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
|
||||
|
||||
"@esbuild/win32-arm64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
|
||||
integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
|
||||
|
||||
"@esbuild/win32-ia32@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
|
||||
integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
|
||||
|
||||
"@esbuild/win32-x64@0.20.2":
|
||||
version "0.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
|
||||
integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
|
||||
@@ -245,6 +355,42 @@
|
||||
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz"
|
||||
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
|
||||
|
||||
"@floating-ui/core@^1.0.0":
|
||||
version "1.6.2"
|
||||
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz"
|
||||
integrity sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==
|
||||
dependencies:
|
||||
"@floating-ui/utils" "^0.2.0"
|
||||
|
||||
"@floating-ui/dom@^1.0.0":
|
||||
version "1.6.5"
|
||||
resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz"
|
||||
integrity sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==
|
||||
dependencies:
|
||||
"@floating-ui/core" "^1.0.0"
|
||||
"@floating-ui/utils" "^0.2.0"
|
||||
|
||||
"@floating-ui/react-dom@^2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz"
|
||||
integrity sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "^1.0.0"
|
||||
|
||||
"@floating-ui/react@^0.26.2":
|
||||
version "0.26.17"
|
||||
resolved "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.17.tgz"
|
||||
integrity sha512-ESD+jYWwqwVzaIgIhExrArdsCL1rOAzryG/Sjlu8yaD3Mtqi3uVyhbE2V7jD58Mo52qbzKz2eUY/Xgh5I86FCQ==
|
||||
dependencies:
|
||||
"@floating-ui/react-dom" "^2.1.0"
|
||||
"@floating-ui/utils" "^0.2.0"
|
||||
tabbable "^6.0.0"
|
||||
|
||||
"@floating-ui/utils@^0.2.0":
|
||||
version "0.2.2"
|
||||
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
|
||||
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.14":
|
||||
version "0.11.14"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
|
||||
@@ -304,7 +450,7 @@
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
@@ -322,11 +468,107 @@
|
||||
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz"
|
||||
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
|
||||
|
||||
"@rollup/plugin-node-resolve@^15.2.3":
|
||||
version "15.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9"
|
||||
integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^5.0.1"
|
||||
"@types/resolve" "1.20.2"
|
||||
deepmerge "^4.2.2"
|
||||
is-builtin-module "^3.2.1"
|
||||
is-module "^1.0.0"
|
||||
resolve "^1.22.1"
|
||||
|
||||
"@rollup/pluginutils@^5.0.1":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0"
|
||||
integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==
|
||||
dependencies:
|
||||
"@types/estree" "^1.0.0"
|
||||
estree-walker "^2.0.2"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27"
|
||||
integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==
|
||||
|
||||
"@rollup/rollup-android-arm64@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203"
|
||||
integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096"
|
||||
integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==
|
||||
|
||||
"@rollup/rollup-darwin-x64@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz"
|
||||
integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8"
|
||||
integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549"
|
||||
integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577"
|
||||
integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c"
|
||||
integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf"
|
||||
integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9"
|
||||
integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec"
|
||||
integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942"
|
||||
integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d"
|
||||
integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf"
|
||||
integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54"
|
||||
integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4"
|
||||
integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==
|
||||
|
||||
"@types/babel__core@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
|
||||
@@ -360,7 +602,7 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.20.7"
|
||||
|
||||
"@types/estree@1.0.5":
|
||||
"@types/estree@1.0.5", "@types/estree@^1.0.0":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz"
|
||||
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
|
||||
@@ -385,6 +627,11 @@
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/resolve@1.20.2":
|
||||
version "1.20.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
|
||||
integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^7":
|
||||
version "7.11.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz"
|
||||
@@ -400,7 +647,7 @@
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/parser@^7", "@typescript-eslint/parser@^7.0.0":
|
||||
"@typescript-eslint/parser@^7":
|
||||
version "7.11.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz"
|
||||
integrity sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==
|
||||
@@ -487,7 +734,7 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
|
||||
acorn@^8.9.0:
|
||||
version "8.11.3"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
|
||||
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
||||
@@ -652,7 +899,7 @@ braces@^3.0.3:
|
||||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
browserslist@^4.22.2, "browserslist@>= 4.21.0":
|
||||
browserslist@^4.22.2:
|
||||
version "4.23.0"
|
||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz"
|
||||
integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==
|
||||
@@ -662,6 +909,11 @@ browserslist@^4.22.2, "browserslist@>= 4.21.0":
|
||||
node-releases "^2.0.14"
|
||||
update-browserslist-db "^1.0.13"
|
||||
|
||||
builtin-modules@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
|
||||
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
|
||||
|
||||
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
|
||||
@@ -719,16 +971,16 @@ color-convert@^2.0.1:
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
||||
@@ -780,6 +1032,11 @@ data-view-byte-offset@^1.0.0:
|
||||
es-errors "^1.3.0"
|
||||
is-data-view "^1.0.1"
|
||||
|
||||
date-fns@^3.3.1, date-fns@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz"
|
||||
integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==
|
||||
|
||||
debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz"
|
||||
@@ -792,6 +1049,11 @@ deep-is@^0.1.3:
|
||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
||||
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
|
||||
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
|
||||
|
||||
define-data-property@^1.0.1, define-data-property@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz"
|
||||
@@ -1053,7 +1315,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
"eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8, eslint@^8.56.0, eslint@>=7:
|
||||
eslint@^8:
|
||||
version "8.57.0"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz"
|
||||
integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==
|
||||
@@ -1125,6 +1387,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
estree-walker@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
|
||||
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
|
||||
@@ -1468,6 +1735,13 @@ is-boolean-object@^1.1.0:
|
||||
call-bind "^1.0.2"
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-builtin-module@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
|
||||
integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
|
||||
dependencies:
|
||||
builtin-modules "^3.3.0"
|
||||
|
||||
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz"
|
||||
@@ -1525,6 +1799,11 @@ is-map@^2.0.3:
|
||||
resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz"
|
||||
integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
|
||||
|
||||
is-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
|
||||
integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
|
||||
|
||||
is-negative-zero@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz"
|
||||
@@ -1735,21 +2014,7 @@ micromatch@^4.0.4:
|
||||
braces "^3.0.3"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
minimatch@^3.0.5:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^3.1.2:
|
||||
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
@@ -1952,12 +2217,12 @@ prettier-plugin-packagejson@^2.5:
|
||||
sort-package-json "2.10.0"
|
||||
synckit "0.9.0"
|
||||
|
||||
prettier@^3, "prettier@>= 1.16.0", prettier@>=2.0:
|
||||
prettier@^3:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz"
|
||||
integrity sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==
|
||||
|
||||
prop-types@^15.8.1:
|
||||
prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@@ -1976,7 +2241,18 @@ queue-microtask@^1.2.2:
|
||||
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
react-dom@^18, react-dom@>=18:
|
||||
react-datepicker@^7.1.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.1.0.tgz"
|
||||
integrity sha512-Z91n5ybhmzI+YChj1ZG7ntPPOmHR2Dh4jbIl+mNgKXKoxyzUQBh7M3eQaFOwrBCVdKy5vsj370/ocQlGu1qsGA==
|
||||
dependencies:
|
||||
"@floating-ui/react" "^0.26.2"
|
||||
clsx "^2.1.0"
|
||||
date-fns "^3.3.1"
|
||||
prop-types "^15.7.2"
|
||||
react-onclickoutside "^6.13.0"
|
||||
|
||||
react-dom@^18:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
|
||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
||||
@@ -1989,6 +2265,11 @@ react-is@^16.13.1:
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-onclickoutside@^6.13.0:
|
||||
version "6.13.1"
|
||||
resolved "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz"
|
||||
integrity sha512-LdrrxK/Yh9zbBQdFbMTXPp3dTSN9B+9YJQucdDu3JNKRrbdU+H+/TVONJoWtOwy4II8Sqf1y/DTI6w/vGPYW0w==
|
||||
|
||||
react-refresh@^0.14.2:
|
||||
version "0.14.2"
|
||||
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz"
|
||||
@@ -2001,7 +2282,7 @@ react-toastify@^10.0.5:
|
||||
dependencies:
|
||||
clsx "^2.1.0"
|
||||
|
||||
react@^18, react@^18.3.1, react@>=18:
|
||||
react@^18:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
|
||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||
@@ -2036,6 +2317,15 @@ resolve-from@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
resolve@^1.22.1:
|
||||
version "1.22.8"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
|
||||
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
|
||||
dependencies:
|
||||
is-core-module "^2.13.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
resolve@^2.0.0-next.5:
|
||||
version "2.0.0-next.5"
|
||||
resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz"
|
||||
@@ -2288,6 +2578,11 @@ synckit@0.9.0:
|
||||
"@pkgr/core" "^0.1.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
tabbable@^6.0.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz"
|
||||
integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
|
||||
@@ -2371,7 +2666,7 @@ typed-array-length@^1.0.6:
|
||||
is-typed-array "^1.1.13"
|
||||
possible-typed-array-names "^1.0.0"
|
||||
|
||||
typescript@^5.4.5, typescript@>=2.9, typescript@>=4.2.0:
|
||||
typescript@^5:
|
||||
version "5.4.5"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz"
|
||||
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
|
||||
@@ -2401,7 +2696,7 @@ uri-js@^4.2.2:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
"vite@^4.2.0 || ^5.0.0", vite@^5.2:
|
||||
vite@^5.2:
|
||||
version "5.2.12"
|
||||
resolved "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz"
|
||||
integrity sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==
|
||||
|
||||
@@ -61,7 +61,7 @@ const handleGET = async (request: Request) => {
|
||||
const params = new URLSearchParams({ castToken });
|
||||
|
||||
let response = await fetch(
|
||||
`https://api.ente.io/cast/files${pathname}${fileID}?${params.toString()}`
|
||||
`https://api.ente.io/cast/files${pathname}${fileID}?${params.toString()}`,
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
@@ -17,16 +17,12 @@ export default {
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
const headers = request.headers.get("Access-Control-Request-Headers");
|
||||
if (!areAllowedHeaders(headers))
|
||||
console.warn("Unknown header in list", headers);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
|
||||
"Access-Control-Allow-Headers": "*",
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -48,16 +44,6 @@ const isAllowedOrigin = (origin: string | null) => {
|
||||
}
|
||||
};
|
||||
|
||||
const areAllowedHeaders = (headers: string | null) => {
|
||||
const allowed = ["x-auth-token", "x-client-package"];
|
||||
|
||||
if (!headers) return true;
|
||||
for (const header of headers.split(",")) {
|
||||
if (!allowed.includes(header.trim().toLowerCase())) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleGET = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
|
||||
@@ -91,7 +77,7 @@ const handleGET = async (request: Request) => {
|
||||
headers: {
|
||||
"User-Agent": request.headers.get("User-Agent") ?? "",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
"wrangler": "^3",
|
||||
"prettier": "^3"
|
||||
},
|
||||
"workspaces": [
|
||||
"*"
|
||||
|
||||
@@ -17,17 +17,13 @@ export default {
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
const headers = request.headers.get("Access-Control-Request-Headers");
|
||||
if (!areAllowedHeaders(headers))
|
||||
console.warn("Unknown header in list", headers);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers":
|
||||
"X-Auth-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Access-Token, X-Auth-Access-Token-JWT",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Access-Token, X-Auth-Access-Token-JWT, x-client-package",
|
||||
"Access-Control-Allow-Headers": "*",
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -45,21 +41,6 @@ const isAllowedOrigin = (origin: string | null) => {
|
||||
}
|
||||
};
|
||||
|
||||
const areAllowedHeaders = (headers: string | null) => {
|
||||
// TODO(MR): Stop sending "x-client-package"
|
||||
const allowed = [
|
||||
"x-auth-access-token",
|
||||
"x-auth-access-token-jwt",
|
||||
"x-client-package",
|
||||
];
|
||||
|
||||
if (!headers) return true;
|
||||
for (const header of headers.split(",")) {
|
||||
if (!allowed.includes(header.trim().toLowerCase())) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleGET = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
|
||||
@@ -90,7 +71,7 @@ const handleGET = async (request: Request) => {
|
||||
if (accessTokenJWT) params.set("accessTokenJWT", accessTokenJWT);
|
||||
|
||||
let response = await fetch(
|
||||
`https://api.ente.io/public-collection/files${pathname}${fileID}?${params.toString()}`
|
||||
`https://api.ente.io/public-collection/files${pathname}${fileID}?${params.toString()}`,
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
@@ -17,16 +17,12 @@ export default {
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
const headers = request.headers.get("Access-Control-Request-Headers");
|
||||
if (!areAllowedHeaders(headers))
|
||||
console.warn("Unknown header in list", headers);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
|
||||
"Access-Control-Allow-Headers": "*",
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -48,16 +44,6 @@ const isAllowedOrigin = (origin: string | null) => {
|
||||
}
|
||||
};
|
||||
|
||||
const areAllowedHeaders = (headers: string | null) => {
|
||||
const allowed = ["x-auth-token", "x-client-package"];
|
||||
|
||||
if (!headers) return true;
|
||||
for (const header of headers.split(",")) {
|
||||
if (!allowed.includes(header.trim().toLowerCase())) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleGET = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
|
||||
@@ -79,7 +65,7 @@ const handleGET = async (request: Request) => {
|
||||
if (token) params.set("token", token);
|
||||
|
||||
let response = await fetch(
|
||||
`https://api.ente.io/files/preview/${fileID}?${params.toString()}`
|
||||
`https://api.ente.io/files/preview/${fileID}?${params.toString()}`,
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
@@ -23,17 +23,14 @@ export default {
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
const headers = request.headers.get("Access-Control-Request-Headers");
|
||||
if (!areAllowedHeaders(headers))
|
||||
console.warn("Unknown header in list", headers);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "POST, PUT, OPTIONS",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
// "Access-Control-Allow-Headers": "Content-Type", "UPLOAD-URL, X-Client-Package",
|
||||
"Access-Control-Allow-Headers": "*",
|
||||
"Access-Control-Allow-Headers":
|
||||
"Content-Type, UPLOAD-URL, X-Client-Package",
|
||||
"Access-Control-Expose-Headers": "X-Request-Id, CF-Ray",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -55,16 +52,6 @@ const isAllowedOrigin = (origin: string | null) => {
|
||||
}
|
||||
};
|
||||
|
||||
const areAllowedHeaders = (headers: string | null) => {
|
||||
const allowed = ["content-type", "upload-url", "x-client-package"];
|
||||
|
||||
if (!headers) return true;
|
||||
for (const header of headers.split(",")) {
|
||||
if (!allowed.includes(header.trim().toLowerCase())) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handlePOSTOrPUT = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
|
||||
@@ -116,7 +103,7 @@ const handlePOSTOrPUT = async (request: Request) => {
|
||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
response.headers.set(
|
||||
"Access-Control-Expose-Headers",
|
||||
"X-Request-Id, CF-Ray"
|
||||
"X-Request-Id, CF-Ray",
|
||||
);
|
||||
return response;
|
||||
};
|
||||
|
||||
BIN
mobile/assets/2.0x/lock_screen_background.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
mobile/assets/3.0x/lock_screen_background.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
mobile/assets/lock_screen_background.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
36
mobile/fastlane/metadata/android/pl/full_description.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
Ente to prosta aplikacja do tworzenia kopii zapasowej Twoich zdjęć i filmów.
|
||||
|
||||
Jeśli szukałeś/aś przyjaznej dla prywatności alternatywy do Google Photos to dotarłeś/aś do właściwego miejsca. Dzięki Ente są one przechowywane w pełni zaszyfrowane (e2ee). Oznacza to, że tylko Ty możesz je oglądać.
|
||||
|
||||
Mamy otwarto-źródłowe aplikacje na wszystkich platformach, a Twoje zdjęcia będą płynnie synchronizowane między Twoimi urządzeniami w sposób szyfrowany end-to-end (e2ee).
|
||||
|
||||
Ente sprawia, że udostępnianie twoich albumów swoim bliskim również jest proste, nawet jeśli nie są w Ente. Możesz udostępniać publicznie widoczne linki, gdzie mogą oglądać twój album i współpracować, dodając do niego zdjęcia, nawet bez konta lub aplikacji.
|
||||
|
||||
Twoje zaszyfrowane dane są przechowywane w wielu lokalizacjach, między innymi w schronie przeciwatomowym w Paryżu. Poważnie podchodzimy do kwestii zachowania pamięci i ułatwiamy zadbanie o to, by wspomnienia przetrwały dłużej niż ty sam.
|
||||
|
||||
Jesteśmy tutaj, aby zrobić najbezpieczniejszą aplikację na zdjęcia, dołącz do naszej podróży!
|
||||
|
||||
FUNKCJE
|
||||
- Oryginalne kopie zapasowe wysokiej jakości, ponieważ każdy piksel jest ważny
|
||||
- Plany rodzinne, umożliwiające współdzielenie pamięci z rodziną
|
||||
- Wspólne albumy, dzięki czemu możesz zbierać zdjęcia po podróży
|
||||
- Udostępnione foldery, jeśli chcesz, aby Twój partner cieszył się kliknięciami "Aparatu"
|
||||
- Linki do albumów, które mogą być chronione hasłem
|
||||
- Możliwość zwolnienia miejsca poprzez usunięcie plików, które zostały bezpiecznie zarchiwizowane
|
||||
- Wsparcie ludzkie, ponieważ jesteś tego warty/a
|
||||
- Opisy, dzięki którym możesz podpisać swoje wspomnienia i łatwo je znaleźć
|
||||
- Edytor obrazów, aby dodać ostatnie poprawki
|
||||
- Dodaj do ulubionych, ukryj i przeżyj swoje wspomnienia, ponieważ są cenne
|
||||
- Import jednym kliknięciem z Google, Apple, dysku twardego i więcej
|
||||
- Ciemny motyw, ponieważ Twoje zdjęcia wyglądają w nim dobrze
|
||||
- 2FA, 3FA, uwierzytelnianie biometryczne
|
||||
- i o WIELE więcej!
|
||||
|
||||
UPRAWNIENIA
|
||||
Ente prosi o określone uprawnienia, aby służyć jako dostawca usług przechowywania zdjęć, które można przejrzeć tutaj: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
|
||||
|
||||
CENNIK
|
||||
Nie oferujemy wiecznie darmowych planów, ponieważ ważne jest dla nas, abyśmy pozostali zrównoważeni i wytrzymali próbę czasu. Zamiast tego oferujemy przystępne cenowo plany, którymi można swobodnie dzielić się z rodziną. Więcej informacji możesz znaleźć na stronie ente.io.
|
||||
|
||||
WSPARCIE
|
||||
Jesteśmy dumni z tego, że oferujemy ludzkie wsparcie. Jeśli jesteś naszym płatnym klientem, możesz skontaktować się z nami pod adresem team@ente.io i oczekiwać odpowiedzi od naszego zespołu w ciągu 24 godzin.
|
||||
@@ -1 +1 @@
|
||||
ente to w pełni szyfrowana aplikacja do przechowywania zdjęć
|
||||
Ente to w pełni szyfrowana aplikacja do przechowywania zdjęć
|
||||
@@ -1 +1 @@
|
||||
ente - szyfrowane przechowywanie zdjęć
|
||||
Ente - szyfrowane przechowywanie zdjęć
|
||||
@@ -1 +1 @@
|
||||
ente Fotos
|
||||
Ente Fotos
|
||||
|
||||
@@ -1 +1 @@
|
||||
ente Fotos
|
||||
Ente Fotos
|
||||
|
||||
1
mobile/fastlane/metadata/ios/gu/keywords.txt
Normal file
@@ -0,0 +1 @@
|
||||
ફોટા,ફોટોગ્રાફી,પરિવાર,ગોપનીયતા,વાદળ,બેકઅપ,વીડિયો,ફોટો,એન્ક્રિપ્શન,સંગ્રહ,આલ્બમ,વૈકલ્પિક
|
||||
@@ -1 +1 @@
|
||||
Ente Photos
|
||||
Ente Foto
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Ente to prosta aplikacja do automatycznego tworzenia kopii zapasowych oraz porządkowania zdjęć i filmów.
|
||||
|
||||
Jeśli szukasz przyjaznej dla prywatności alternatywy, aby zachować swoje wspomnienia, jesteś we właściwym miejscu. Dzięki Ente są one przechowywane w pełni zaszyfrowane (e2ee). Oznacza to, że tylko Ty możesz je oglądać.
|
||||
Jeśli szukałeś/aś przyjaznej dla prywatności alternatywy, aby zachować swoje wspomnienia, to dotarłeś/aś do właściwego miejsca. Dzięki Ente są one przechowywane w pełni zaszyfrowane (e2ee). Oznacza to, że tylko Ty możesz je oglądać.
|
||||
|
||||
Mamy aplikacje na wszystkich platformach, a Twoje zdjęcia będą płynnie synchronizowane między Twoimi urządzeniami w sposób szyfrowany (e2ee).
|
||||
Mamy aplikacje na wszystkich platformach, a Twoje zdjęcia będą płynnie synchronizowane między Twoimi urządzeniami w sposób szyfrowany end-to-end (e2ee).
|
||||
|
||||
Ente ułatwia również udostępnianie albumów najbliższym. Możesz udostępniać je bezpośrednio innym użytkownikom Ente, w pełni zaszyfrowane; lub za pomocą publicznie dostępnych linków.
|
||||
|
||||
@@ -23,11 +23,11 @@ FUNKCJE
|
||||
- 2FA, 3FA, uwierzytelnianie biometryczne
|
||||
- i o WIELE więcej!
|
||||
|
||||
WARUNKI
|
||||
CENNIK
|
||||
Nie oferujemy planów darmowych na zawsze, ponieważ ważne jest dla nas, abyśmy pozostali zrównoważeni i wytrzymali próbę czasu. Zamiast tego oferujemy przystępne cenowo plany, którymi można swobodnie dzielić się z rodziną. Więcej informacji możesz znaleźć na stronie ente.io.
|
||||
|
||||
WSPARCIE
|
||||
Jesteśmy dumni z tego, że oferujemy ludzkie wsparcie. Jeśli jesteś naszym płatnym klientem, możesz skontaktować się z nami pod adresem team@ente.io i oczekiwać odpowiedzi od naszego zespołu w ciągu 24 godzin.
|
||||
|
||||
CENA
|
||||
WARUNKI
|
||||
https://ente.io/terms
|
||||
|
||||
@@ -1 +1 @@
|
||||
ente Zdjęcia
|
||||
Ente Zdjęcia
|
||||
|
||||
@@ -1 +1 @@
|
||||
ente Fotos
|
||||
Ente Fotos
|
||||
|
||||
@@ -1 +1 @@
|
||||
ente Фото
|
||||
Фотографии Ente
|
||||
|
||||
@@ -1 +1 @@
|
||||
ente 照片
|
||||
Ente 照片
|
||||
|
||||
@@ -1 +1 @@
|
||||
ente Fotos
|
||||
Ente Fotos
|
||||
@@ -1 +1 @@
|
||||
ente Fotos
|
||||
Ente Fotos
|
||||
@@ -1 +1 @@
|
||||
Ente Photos
|
||||
Ente Foto
|
||||