Compare commits
425 Commits
cli-v0.1.1
...
swipe_to_s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0ff71828a | ||
|
|
28d9775203 | ||
|
|
c70c6ac617 | ||
|
|
28107cc7ea | ||
|
|
8711753d6f | ||
|
|
b68d11ffbc | ||
|
|
ac0235a6be | ||
|
|
8116b05a9d | ||
|
|
3f49395ee2 | ||
|
|
2d80ed7332 | ||
|
|
5ca0be9f2b | ||
|
|
e0b2fa5a1b | ||
|
|
a58e9030a0 | ||
|
|
1c7fe80663 | ||
|
|
ce701099f0 | ||
|
|
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 | ||
|
|
92b4d52a40 | ||
|
|
083b7b3d95 | ||
|
|
e2e36e285f | ||
|
|
c5bcc1992c | ||
|
|
2c9b0e77ba | ||
|
|
ca7096b87c | ||
|
|
3a8b2cf7b8 | ||
|
|
69bfaf2033 | ||
|
|
0d12f17576 | ||
|
|
80d5d7e44e | ||
|
|
bfa4806d47 | ||
|
|
2c3bd39ab6 | ||
|
|
1d0cbc527a | ||
|
|
4c8e6853be | ||
|
|
4839aaaf6d | ||
|
|
7cac870a68 | ||
|
|
a5a7c4fcb2 | ||
|
|
3d91e1c481 | ||
|
|
3193139118 | ||
|
|
c354c80b1f | ||
|
|
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 | ||
|
|
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 | ||
|
|
279bdc1e66 | ||
|
|
169e70cc0f | ||
|
|
f108ee2bff | ||
|
|
e390d73af4 | ||
|
|
0f1d45587e | ||
|
|
5854a9e10a | ||
|
|
94cd1991ce | ||
|
|
46644d9d4d | ||
|
|
93dec0a9f4 | ||
|
|
c79507a5d4 | ||
|
|
a170acb28b | ||
|
|
7a2f08f49a | ||
|
|
6ea003a9a1 | ||
|
|
c54c4022ad | ||
|
|
445af59829 | ||
|
|
7f573f2181 | ||
|
|
a9dc8da07c | ||
|
|
c2d2612f33 | ||
|
|
3aa3fbba6d | ||
|
|
35c8970d20 | ||
|
|
0f076e19be | ||
|
|
306430d67d | ||
|
|
a28c983c06 | ||
|
|
53140de879 | ||
|
|
3c5ea83f8a | ||
|
|
a59ca2bdf0 | ||
|
|
47ad7c7827 | ||
|
|
516c67e6e9 | ||
|
|
e7970df6cf | ||
|
|
3ac4294c2c | ||
|
|
c8451ecc64 | ||
|
|
f5a31397f3 | ||
|
|
11b443a3f9 | ||
|
|
c95605127d | ||
|
|
7bce4e25ae | ||
|
|
19383ad360 | ||
|
|
0b426fc1ab | ||
|
|
81b07e772d | ||
|
|
65770ff58b | ||
|
|
bf926fe4b6 | ||
|
|
fccf7e3149 | ||
|
|
4042a5876e | ||
|
|
de36d1f9fb | ||
|
|
18fb24fcd2 | ||
|
|
5687f75b0b | ||
|
|
be82595e82 | ||
|
|
d200bce7ea | ||
|
|
05e490aa91 | ||
|
|
716f5f1be2 | ||
|
|
a0d8dd9b9e | ||
|
|
897245d6c1 | ||
|
|
99e4d098e3 | ||
|
|
b276344f1e | ||
|
|
e77ebef801 | ||
|
|
32757c3fb6 | ||
|
|
411e444295 | ||
|
|
abca5bc798 | ||
|
|
8841dd44c4 | ||
|
|
316a5e7209 | ||
|
|
2e53dcca00 | ||
|
|
87e2a32d49 | ||
|
|
af11ff21f4 | ||
|
|
aab7e39ab3 | ||
|
|
595d6f894e | ||
|
|
02a4e2b1ca | ||
|
|
7c535adff1 | ||
|
|
c8effce8fc | ||
|
|
2855181de9 | ||
|
|
25515c4403 | ||
|
|
e7b15b67d8 | ||
|
|
30dd41e3ca | ||
|
|
f8f43b8ab7 | ||
|
|
662210b168 | ||
|
|
2f60894e59 | ||
|
|
da9262da79 | ||
|
|
29539d9db2 | ||
|
|
c4df9c7bd4 | ||
|
|
37296806d6 | ||
|
|
14e0afd867 | ||
|
|
08ceb0d5f2 | ||
|
|
1e83ef0c06 | ||
|
|
47eef986d7 | ||
|
|
378618ac1f | ||
|
|
01c1ae3b97 | ||
|
|
ebd35c62ec | ||
|
|
34753b5786 | ||
|
|
56b62d8b1b | ||
|
|
705dd1bee9 | ||
|
|
921ddac630 | ||
|
|
c8158737f6 | ||
|
|
398ce9d445 | ||
|
|
933ab3ac2c | ||
|
|
b798dacaf2 | ||
|
|
c3e94a405f | ||
|
|
22e09de07a | ||
|
|
492d4f0fd7 | ||
|
|
b9556a91a0 | ||
|
|
950d6a9622 | ||
|
|
e2da01dd5b | ||
|
|
6954c960d8 | ||
|
|
0c790e64f8 | ||
|
|
477bc4ca92 | ||
|
|
9bf8e16978 | ||
|
|
deace2bccd | ||
|
|
f78e01ecd5 | ||
|
|
1a9e1d7d77 | ||
|
|
1481c16b31 | ||
|
|
15baf7d0fb | ||
|
|
15f4e5cae8 | ||
|
|
3321d58455 | ||
|
|
38e1208591 | ||
|
|
0588c32b52 | ||
|
|
feaf8e3a8d | ||
|
|
72584e49d6 | ||
|
|
21f269c999 | ||
|
|
0e92a56378 | ||
|
|
e560eaeb41 | ||
|
|
753801c401 | ||
|
|
057ea875c9 | ||
|
|
dfcd254668 | ||
|
|
541ed4fdba | ||
|
|
278e40639f | ||
|
|
93d1813f97 | ||
|
|
8c0d21ea25 | ||
|
|
ae93fbf45e | ||
|
|
53cb013576 | ||
|
|
a4ff0f0fd8 | ||
|
|
cd56583a56 | ||
|
|
42ac43ed90 | ||
|
|
face4bb55b | ||
|
|
c6110087d9 | ||
|
|
b89968ca47 | ||
|
|
f9588cf1c8 | ||
|
|
04fd2f8007 | ||
|
|
b52192df6a | ||
|
|
95cf85e573 | ||
|
|
6ed2ad0d28 | ||
|
|
5d61750508 | ||
|
|
22cf4eb1fb | ||
|
|
431ad66723 | ||
|
|
6dfac5643a | ||
|
|
46b9aa259c | ||
|
|
d7a1bf3fcc | ||
|
|
b7d3e5439a | ||
|
|
cca1b1971f | ||
|
|
e6a47b29bb | ||
|
|
a10562018c | ||
|
|
2a905a439c | ||
|
|
ef37a4cad8 | ||
|
|
2fcbebd375 | ||
|
|
c50366ce3b | ||
|
|
70a33ca0b8 | ||
|
|
b89378e838 | ||
|
|
00f59dc842 | ||
|
|
64470e156a | ||
|
|
5fbca87998 | ||
|
|
ce989b786f | ||
|
|
480a86af0a | ||
|
|
8a9d196282 | ||
|
|
a5b0bc259d | ||
|
|
848f3a0f6b | ||
|
|
0ee2da9028 | ||
|
|
7edfc15b67 | ||
|
|
e3e6e8e244 | ||
|
|
089d1a2389 | ||
|
|
a099869ecc | ||
|
|
d282ef2eae | ||
|
|
bcca58d5c0 | ||
|
|
ff0fa9a69f | ||
|
|
852e3a59a3 | ||
|
|
5bad7dcb7a | ||
|
|
23f6da17c4 | ||
|
|
b22af43e8a | ||
|
|
36e3907dfc | ||
|
|
38ee01017a | ||
|
|
ec81300971 | ||
|
|
bd239241d7 | ||
|
|
9951e8def4 | ||
|
|
76993961f0 | ||
|
|
29805bdf4d | ||
|
|
7fb2956a2e | ||
|
|
ec82518639 | ||
|
|
b4cd1c715f | ||
|
|
9603c284dc | ||
|
|
a638f9b4a1 | ||
|
|
606b0c35bb | ||
|
|
326e673d12 | ||
|
|
804fc71538 | ||
|
|
eebfb27e5e | ||
|
|
d18e257788 | ||
|
|
adec30a01e | ||
|
|
1aa3e9ac56 | ||
|
|
ad406a0f0b | ||
|
|
6d6eae4c11 | ||
|
|
772e3f2ebd | ||
|
|
00b68131a8 | ||
|
|
de8d81300f | ||
|
|
e287e80257 | ||
|
|
d716f18c2e | ||
|
|
396651b2b5 | ||
|
|
077d509c23 | ||
|
|
062b3f7176 | ||
|
|
a2a295308d | ||
|
|
ffcda13a4e | ||
|
|
9f4ce085c1 | ||
|
|
ff1e84d0d8 | ||
|
|
4f18fff36b | ||
|
|
e1f7b04aa0 | ||
|
|
533c0230e4 | ||
|
|
1e8f739ef2 | ||
|
|
befcb72b04 | ||
|
|
f001812a1d | ||
|
|
1b993a617a | ||
|
|
f04e54f68b | ||
|
|
93bddbe6f1 | ||
|
|
17e48ed83f | ||
|
|
4c7583240f |
31
.github/workflows/auth-crowdin-push.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: "Push sources to Crowdin (auth)"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
# Run workflow when auth's intl_en.arb is changed
|
||||
- "auth/lib/l10n/arb/app_en.arb"
|
||||
# Or the workflow itself is changed
|
||||
- ".github/workflows/auth-crowdin.yml"
|
||||
|
||||
jobs:
|
||||
push-sources-to-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin's action
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_path: "auth/"
|
||||
config: "auth/crowdin.yml"
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
project_id: 575169
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
@@ -1,17 +1,10 @@
|
||||
name: "Sync Crowdin translations (auth)"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
# Run workflow when auth's intl_en.arb is changed
|
||||
- "mobile/lib/l10n/arb/app_en.arb"
|
||||
# Or the workflow itself is changed
|
||||
- ".github/workflows/auth-crowdin.yml"
|
||||
schedule:
|
||||
# See: [Note: Run workflow on specific days of the week]
|
||||
- cron: "50 1 * * 2,5"
|
||||
# Also allow manually running the workflow
|
||||
- cron: "50 1 * * 2"
|
||||
# Also allow manually running the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -23,7 +16,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin's action
|
||||
uses: crowdin/github-action@v1
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_path: "auth/"
|
||||
config: "auth/crowdin.yml"
|
||||
12
.github/workflows/auth-release.yml
vendored
@@ -145,7 +145,7 @@ jobs:
|
||||
- name: Install dependencies for desktop build
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libsecret-1-dev libsodium-dev libwebkit2gtk-4.0-dev libfuse2 ninja-build libgtk-3-dev dpkg-dev pkg-config rpm patchelf libsqlite3-dev locate libayatana-appindicator3-dev libffi-dev libtiff5
|
||||
sudo apt-get install -y libsecret-1-dev libsodium-dev libwebkit2gtk-4.0-dev libfuse2 ninja-build libgtk-3-dev dpkg-dev pkg-config rpm patchelf libsqlite3-dev locate libayatana-appindicator3-dev libffi-dev libtiff5 xz-utils libarchive-tools
|
||||
sudo updatedb --localpaths='/usr/lib/x86_64-linux-gnu'
|
||||
|
||||
- name: Install appimagetool
|
||||
@@ -157,10 +157,16 @@ jobs:
|
||||
- name: Build desktop app
|
||||
run: |
|
||||
flutter config --enable-linux-desktop
|
||||
dart pub global activate flutter_distributor
|
||||
# dart pub global activate flutter_distributor
|
||||
dart pub global activate --source git https://github.com/prateekmedia/flutter_distributor --git-ref pacman --git-path packages/flutter_distributor
|
||||
# Run below command if it is a beta or nightly
|
||||
if [[ ${{ github.ref }} =~ beta|nightly ]]; then
|
||||
flutter_distributor package --platform=linux --targets=pacman --skip-clean
|
||||
mv dist/**/*-*-linux.pacman artifacts/ente-${{ github.ref_name }}-x86_64.pacman
|
||||
fi
|
||||
flutter_distributor package --platform=linux --targets=rpm --skip-clean
|
||||
flutter_distributor package --platform=linux --targets=appimage --skip-clean
|
||||
mv dist/**/*-*-linux.rpm artifacts/ente-${{ github.ref_name }}-x86_64.rpm
|
||||
flutter_distributor package --platform=linux --targets=appimage --skip-clean
|
||||
mv dist/**/*-*-linux.AppImage artifacts/ente-${{ github.ref_name }}-x86_64.AppImage
|
||||
|
||||
- name: Generate checksums
|
||||
|
||||
31
.github/workflows/mobile-crowdin-push.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: "Push sources to Crowdin (mobile)"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
# Run workflow when mobiles's intl_en.arb is changed
|
||||
- "mobile/lib/l10n/intl_en.arb"
|
||||
# Or the workflow itself is changed
|
||||
- ".github/workflows/mobile-crowdin.yml"
|
||||
|
||||
jobs:
|
||||
push-sources-to-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin's action
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_path: "mobile/"
|
||||
config: "mobile/crowdin.yml"
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
project_id: 574741
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
@@ -1,17 +1,10 @@
|
||||
name: "Sync Crowdin translations (mobile)"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
# Run workflow when mobiles's intl_en.arb is changed
|
||||
- "mobile/lib/l10n/intl_en.arb"
|
||||
# Or the workflow itself is changed
|
||||
- ".github/workflows/mobile-crowdin.yml"
|
||||
schedule:
|
||||
# See: [Note: Run workflow on specific days of the week]
|
||||
- cron: "40 1 * * 2,5"
|
||||
# Also allow manually running the workflow
|
||||
- cron: "40 1 * * 2"
|
||||
# Also allow manually running the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -23,7 +16,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin's action
|
||||
uses: crowdin/github-action@v1
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_path: "mobile/"
|
||||
config: "mobile/crowdin.yml"
|
||||
@@ -1,6 +1,6 @@
|
||||
name: "Push Crowdin translations (web)"
|
||||
|
||||
# This is a variant of web-crowdin.yml that uploads the translated strings in
|
||||
# This is a variant of web-crowdin-sync.yml that uploads the translated strings in
|
||||
# addition to the source strings.
|
||||
#
|
||||
# This allows us to change the strings in our source code for an automated
|
||||
@@ -9,11 +9,11 @@ name: "Push Crowdin translations (web)"
|
||||
|
||||
on:
|
||||
# Trigger manually, or using
|
||||
# `gh workflow run web-crowdin-push.yml --ref <my-branch>`
|
||||
# `gh workflow run web-crowdin-push-both.yml --ref <my-branch>`
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
push-to-crowdin:
|
||||
push-both-to-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin push
|
||||
uses: crowdin/github-action@v1
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_path: "web/"
|
||||
config: "web/crowdin.yml"
|
||||
@@ -16,8 +16,8 @@ on:
|
||||
# and FRI, this can be set to `2,5`.
|
||||
#
|
||||
# See also: [Note: Run workflow every 24 hours]
|
||||
- cron: "20 1 * * 2,5"
|
||||
# Also allow manually running the workflow
|
||||
- cron: "20 1 * * 2"
|
||||
# Also allow manually running the workflow.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Crowdin's action
|
||||
uses: crowdin/github-action@v1
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_path: "web/"
|
||||
config: "web/crowdin.yml"
|
||||
15
.github/workflows/web-deploy-staging.yml
vendored
@@ -1,5 +1,7 @@
|
||||
name: "Deploy staging (web)"
|
||||
|
||||
# Builds the "staging/web" branch if it exists, "main" otherwise.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run everyday at ~3:00 PM IST
|
||||
@@ -18,9 +20,20 @@ jobs:
|
||||
working-directory: web
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
- name: Determine branch to build
|
||||
id: select-branch
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
if git ls-remote --exit-code --heads https://github.com/ente-io/ente refs/heads/staging/web; then
|
||||
echo "branch=staging/web" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "branch=main" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Checkout ${{ steps.select-branch.outputs.branch }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ steps.select-branch.outputs.branch }}
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup node and enable yarn caching
|
||||
|
||||
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-----
|
||||
@@ -39,11 +39,15 @@
|
||||
{
|
||||
"title": "Bloom Host",
|
||||
"slug": "bloom_host",
|
||||
"altNames": ["Bloom Host Billing"]
|
||||
"altNames": [
|
||||
"Bloom Host Billing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "BorgBase",
|
||||
"altNames": ["borg"],
|
||||
"altNames": [
|
||||
"borg"
|
||||
],
|
||||
"slug": "BorgBase"
|
||||
},
|
||||
{
|
||||
@@ -67,6 +71,13 @@
|
||||
{
|
||||
"title": "Cloudflare"
|
||||
},
|
||||
{
|
||||
"title": "CloudAMQP"
|
||||
},
|
||||
{
|
||||
"title": "ConfigCat",
|
||||
"slug": "configcat"
|
||||
},
|
||||
{
|
||||
"title": "CoinDCX"
|
||||
},
|
||||
@@ -83,7 +94,9 @@
|
||||
},
|
||||
{
|
||||
"title": "DCS",
|
||||
"altNames": ["Digital Combat Simulator"],
|
||||
"altNames": [
|
||||
"Digital Combat Simulator"
|
||||
],
|
||||
"slug": "dcs"
|
||||
},
|
||||
{
|
||||
@@ -143,7 +156,9 @@
|
||||
},
|
||||
{
|
||||
"title": "Gosuslugi",
|
||||
"altNames": ["Госуслуги"],
|
||||
"altNames": [
|
||||
"Госуслуги"
|
||||
],
|
||||
"slug": "Gosuslugi"
|
||||
},
|
||||
{
|
||||
@@ -219,7 +234,11 @@
|
||||
{
|
||||
"title": "Local",
|
||||
"slug": "local_wp",
|
||||
"altNames": ["LocalWP", "Local WP", "Local Wordpress"]
|
||||
"altNames": [
|
||||
"LocalWP",
|
||||
"Local WP",
|
||||
"Local Wordpress"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Marketplace.tf",
|
||||
@@ -227,14 +246,23 @@
|
||||
},
|
||||
{
|
||||
"title": "Mastodon",
|
||||
"altNames": ["mstdn", "fediscience", "mathstodon", "fosstodon"],
|
||||
"altNames": [
|
||||
"mstdn",
|
||||
"fediscience",
|
||||
"mathstodon",
|
||||
"fosstodon"
|
||||
],
|
||||
"slug": "mastodon",
|
||||
"hex": "6364FF"
|
||||
},
|
||||
{
|
||||
"title": "Mercado Livre",
|
||||
"slug": "mercado_livre",
|
||||
"altNames": ["Mercado Libre", "MercadoLibre", "MercadoLivre"]
|
||||
"altNames": [
|
||||
"Mercado Libre",
|
||||
"MercadoLibre",
|
||||
"MercadoLivre"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Microsoft"
|
||||
@@ -250,7 +278,9 @@
|
||||
},
|
||||
{
|
||||
"title": "Murena",
|
||||
"altNames": ["eCloud"],
|
||||
"altNames": [
|
||||
"eCloud"
|
||||
],
|
||||
"slug": "ecloud"
|
||||
},
|
||||
{
|
||||
@@ -277,6 +307,10 @@
|
||||
{
|
||||
"title": "Notion"
|
||||
},
|
||||
{
|
||||
"title": "NuCommunity",
|
||||
"slug": "nucommunity"
|
||||
},
|
||||
{
|
||||
"title": "NVIDIA"
|
||||
},
|
||||
@@ -335,8 +369,16 @@
|
||||
"slug": "real_debrid"
|
||||
},
|
||||
{
|
||||
"title": "Registro.br",
|
||||
"slug": "registro_br"
|
||||
"title": "Registro br",
|
||||
"slug": "registro_br",
|
||||
"altNames": [
|
||||
"Registro br",
|
||||
"registrobr",
|
||||
"Registro.br"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Render"
|
||||
},
|
||||
{
|
||||
"title": "Revolt",
|
||||
@@ -355,6 +397,9 @@
|
||||
"slug": "rust_language_forum",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "Samsung"
|
||||
},
|
||||
{
|
||||
"title": "Sendgrid"
|
||||
},
|
||||
@@ -396,7 +441,10 @@
|
||||
},
|
||||
{
|
||||
"title": "Techlore",
|
||||
"altNames": ["Techlore Courses", "Techlore Forums"]
|
||||
"altNames": [
|
||||
"Techlore Courses",
|
||||
"Techlore Forums"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Termius",
|
||||
@@ -426,6 +474,13 @@
|
||||
"title": "Twingate",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "Twitch",
|
||||
"altNames": [
|
||||
"Twitch.tv",
|
||||
"Twitch tv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Ubisoft",
|
||||
"hex": "4285f4"
|
||||
@@ -460,23 +515,32 @@
|
||||
{
|
||||
"title": "WorkOS",
|
||||
"slug": "workos",
|
||||
"altNames": ["Work OS"]
|
||||
"altNames": [
|
||||
"Work OS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "X",
|
||||
"altNames": ["twitter"],
|
||||
"altNames": [
|
||||
"twitter"
|
||||
],
|
||||
"slug": "x"
|
||||
},
|
||||
{
|
||||
"title": "Yandex",
|
||||
"altNames": ["Ya", "Яндекс"],
|
||||
"altNames": [
|
||||
"Ya",
|
||||
"Яндекс"
|
||||
],
|
||||
"slug": "Yandex"
|
||||
},
|
||||
{
|
||||
"title": "YNAB",
|
||||
"altNames": ["You Need A Budget"],
|
||||
"altNames": [
|
||||
"You Need A Budget"
|
||||
],
|
||||
"slug": "ynab",
|
||||
"hex": "3B5EDA"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
19
auth/assets/custom-icons/icons/cloudamqp.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="512px" height="512px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:1" fill="#0f0f0f" d="M 511.5,272.5 C 511.5,285.5 511.5,298.5 511.5,311.5C 508.543,328.958 502.376,345.291 493,360.5C 489.783,363.38 486.95,366.547 484.5,370C 491.258,380.639 489.591,389.639 479.5,397C 464.044,407.934 447.377,416.601 429.5,423C 412.83,426.168 399.163,421.335 388.5,408.5C 367.197,419.324 344.531,424.491 320.5,424C 318.692,436.612 312.359,446.279 301.5,453C 283.703,460.911 265.036,464.411 245.5,463.5C 242.9,471.276 237.9,477.109 230.5,481C 217.623,486.044 204.289,487.711 190.5,486C 185.821,485.662 181.488,484.328 177.5,482C 156.539,481.714 144.039,471.214 140,450.5C 127.176,458.148 113.343,460.648 98.5,458C 90.6339,455.515 82.6339,453.515 74.5,452C 54.9132,442.997 49.0799,428.497 57,408.5C 66.2342,395.627 78.7342,387.961 94.5,385.5C 92.6275,381.588 90.6275,377.755 88.5,374C 70.6568,365.82 58.8235,352.32 53,333.5C 40.7936,289.193 46.2936,247.193 69.5,207.5C 59.4487,191.064 51.2821,173.73 45,155.5C 46.0538,140.201 46.3871,124.867 46,109.5C 35.4808,94.9732 23.4808,81.6398 10,69.5C 6.25674,65.2678 2.75674,60.9345 -0.5,56.5C -0.5,52.1667 -0.5,47.8333 -0.5,43.5C 9.76623,24.2659 25.0996,18.7659 45.5,27C 67.9457,36.2887 85.1124,51.4554 97,72.5C 110.456,95.0753 121.456,118.742 130,143.5C 131.478,149.551 132.812,155.551 134,161.5C 150.985,156.607 167.819,150.94 184.5,144.5C 189.063,124.296 197.563,105.963 210,89.5C 221.355,76.4675 234.189,65.3008 248.5,56C 281.602,35.3661 304.768,43.1994 318,79.5C 320.953,90.3093 322.453,101.309 322.5,112.5C 360.236,109.787 395.903,116.953 429.5,134C 465.163,161.014 489.997,195.848 504,238.5C 507.153,249.807 509.653,261.14 511.5,272.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#f9f9f9" d="M 24.5,29.5 C 29.5518,29.4502 34.5518,29.9502 39.5,31C 64.2651,40.4294 82.7651,56.9294 95,80.5C 105.37,98.9048 114.37,117.905 122,137.5C 124.445,145.715 126.278,154.048 127.5,162.5C 112.806,166.18 99.806,173.013 88.5,183C 87.6683,183.688 87.0016,183.521 86.5,182.5C 81.5074,171.354 77.0074,160.021 73,148.5C 71.949,132.503 70.949,116.503 70,100.5C 69.8323,89.9943 66.4989,80.661 60,72.5C 50.2229,59.4865 39.3896,47.3198 27.5,36C 24.3562,34.3084 21.0229,33.1418 17.5,32.5C 19.7639,31.1308 22.0972,30.1308 24.5,29.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#f8a38f" d="M 12.5,38.5 C 17.3236,37.9711 21.6569,39.1378 25.5,42C 39.5654,55.7226 51.7321,70.8893 62,87.5C 64.8374,107.385 66.5041,127.385 67,147.5C 70.9051,161.478 76.0717,174.978 82.5,188C 79.7313,192.44 76.5646,196.606 73,200.5C 64.0573,185.948 56.724,170.614 51,154.5C 51.9952,139.197 52.3286,123.864 52,108.5C 48.7377,102.307 44.7377,96.6405 40,91.5C 29,79.8333 18,68.1667 7,56.5C 3.70863,48.8182 5.54196,42.8182 12.5,38.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fafafa" d="M 75.5,358.5 C 75.5,358.167 75.5,357.833 75.5,357.5C 89.9869,361.531 96.4869,355.865 95,340.5C 88.9149,339.688 82.7482,339.188 76.5,339C 72.7424,337.077 69.4091,334.577 66.5,331.5C 65.914,331.709 65.414,332.043 65,332.5C 64.3219,336.221 64.4886,339.888 65.5,343.5C 65.5,344.167 65.5,344.833 65.5,345.5C 56.2828,328.814 51.9494,310.814 52.5,291.5C 52.6554,251.963 65.6554,217.463 91.5,188C 109.872,171.873 131.372,164.04 156,164.5C 163.871,164.941 171.705,165.774 179.5,167C 180.059,167.725 180.392,168.558 180.5,169.5C 177.315,184.684 175.315,200.018 174.5,215.5C 176.5,215.5 178.5,215.5 180.5,215.5C 182.202,180.727 189.035,147.061 201,114.5C 217.196,84.2957 241.363,63.4624 273.5,52C 285.541,49.4426 295.374,52.9426 303,62.5C 310.113,73.413 314.447,85.413 316,98.5C 321.979,137.67 310.146,170.17 280.5,196C 263.081,211.714 243.415,223.881 221.5,232.5C 221.08,234.326 221.08,236.326 221.5,238.5C 234.851,234.241 247.351,228.241 259,220.5C 259.772,220.645 260.439,220.978 261,221.5C 275.359,247.499 277.359,274.499 267,302.5C 255.866,325.636 239.699,344.469 218.5,359C 205.461,365.355 191.794,369.689 177.5,372C 152.14,376.37 126.806,376.37 101.5,372C 91.2074,370.356 82.5408,365.856 75.5,358.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#0f0c0c" d="M 193.5,223.5 C 192.507,215.35 192.174,207.017 192.5,198.5C 193.5,169.804 200.666,142.804 214,117.5C 225.84,98.1554 243.007,87.1554 265.5,84.5C 286.335,85.1601 299.835,95.4934 306,115.5C 309.914,142.091 302.081,164.591 282.5,183C 256.19,203.482 226.523,216.982 193.5,223.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fca592" d="M 257.5,90.5 C 284.894,88.5662 299.56,101.233 301.5,128.5C 300.608,150.45 291.608,168.284 274.5,182C 251.674,198.494 226.507,209.994 199,216.5C 197.361,188.998 201.361,162.331 211,136.5C 219.834,114.165 235.334,98.8314 257.5,90.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fafafa" d="M 60.5,425.5 C 59.5386,423.735 59.2053,421.735 59.5,419.5C 63.1115,407.716 70.7781,399.549 82.5,395C 91.0632,391.633 99.5632,391.799 108,395.5C 108.667,394.833 108.667,394.167 108,393.5C 102.81,388.767 99.4764,383.1 98,376.5C 102.705,378.033 107.538,379.2 112.5,380C 140.837,382.162 168.837,380.162 196.5,374C 217.812,367.925 235.645,356.425 250,339.5C 264.443,322.614 274.11,303.281 279,281.5C 281.871,258.038 277.038,236.371 264.5,216.5C 281.854,203.979 296.687,188.979 309,171.5C 318.099,155.03 322.599,137.363 322.5,118.5C 360.451,115.776 396.117,123.276 429.5,141C 473.317,176.458 498.484,222.292 505,278.5C 507.615,302.611 503.949,325.611 494,347.5C 489.686,356.123 483.52,363.123 475.5,368.5C 480.461,372.751 482.961,378.085 483,384.5C 480.5,388.333 477.333,391.5 473.5,394C 459.716,403.227 445.049,410.893 429.5,417C 425.514,417.499 421.514,417.666 417.5,417.5C 417.193,411.907 417.527,406.407 418.5,401C 417.167,400.333 415.833,399.667 414.5,399C 430.794,394.523 446.461,388.356 461.5,380.5C 461.014,378.503 459.847,377.169 458,376.5C 440.722,385.148 422.555,390.982 403.5,394C 380.37,396.219 367.203,385.719 364,362.5C 362.937,347.817 366.437,334.317 374.5,322C 373.465,320.726 372.298,319.56 371,318.5C 354.722,340.239 353.389,362.905 367,386.5C 371.262,392.27 376.762,396.27 383.5,398.5C 384.736,400.034 385.236,401.7 385,403.5C 364.91,414.289 343.41,418.956 320.5,417.5C 319.84,404.55 317.673,391.883 314,379.5C 311.816,377.129 309.65,377.296 307.5,380C 314.177,397.067 315.677,414.567 312,432.5C 305.593,444.224 295.76,451.39 282.5,454C 268.581,456.057 254.581,457.224 240.5,457.5C 239.833,466.67 235.166,472.837 226.5,476C 215.527,480.056 204.193,481.39 192.5,480C 187.997,479.932 183.83,478.765 180,476.5C 179.18,467.46 181.68,459.46 187.5,452.5C 186.167,451.5 184.833,450.5 183.5,449.5C 176.525,456.706 173.192,465.372 173.5,475.5C 155.566,474.56 151.066,466.227 160,450.5C 165.03,445.927 164.364,443.594 158,443.5C 153.995,448.511 151.328,454.178 150,460.5C 149.667,460.167 149.333,459.833 149,459.5C 144.897,446.475 148.397,435.975 159.5,428C 163.945,425.443 168.611,423.443 173.5,422C 182.977,422.438 192.477,422.938 202,423.5C 220.978,425.676 230.811,417.343 231.5,398.5C 229.5,398.5 227.5,398.5 225.5,398.5C 226.791,409.364 222.125,415.864 211.5,418C 200.619,418.627 189.786,418.127 179,416.5C 166.002,416.349 155.502,421.349 147.5,431.5C 146.029,427.759 144.363,424.092 142.5,420.5C 141.998,419.479 141.332,419.312 140.5,420C 139.272,420.779 138.272,421.779 137.5,423C 139.652,428.271 141.652,433.604 143.5,439C 129.108,453.41 112.441,456.91 93.5,449.5C 89.7245,439.648 91.3911,430.815 98.5,423C 97.3147,421.647 95.9814,420.48 94.5,419.5C 87.1734,427.469 84.5067,436.803 86.5,447.5C 75.3584,448.43 68.025,443.597 64.5,433C 65.9688,424.073 69.6355,416.239 75.5,409.5C 74.5,407.833 73.1667,406.5 71.5,405.5C 66.2677,411.297 62.601,417.964 60.5,425.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e5e5e5" d="M 180.5,151.5 C 181.675,151.281 182.675,151.614 183.5,152.5C 182.878,155.37 182.211,158.204 181.5,161C 175.174,160.8 168.84,160.134 162.5,159C 168.652,156.569 174.652,154.069 180.5,151.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#9b9b9b" d="M 192.5,198.5 C 192.174,207.017 192.507,215.35 193.5,223.5C 193.44,224.043 193.107,224.376 192.5,224.5C 191.179,215.675 191.179,207.009 192.5,198.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#090909" d="M 190.5,275.5 C 203.491,273.992 208.658,279.659 206,292.5C 201.745,299.54 195.578,302.04 187.5,300C 181.092,296.677 178.925,291.511 181,284.5C 183.679,280.924 186.846,277.924 190.5,275.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#dddddd" d="M 192.5,279.5 C 196.302,278.88 199.635,279.714 202.5,282C 201.646,283.022 200.646,283.855 199.5,284.5C 197.382,283.054 195.049,282.387 192.5,282.5C 192.5,281.5 192.5,280.5 192.5,279.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#070707" d="M 75.5,357.5 C 71.1612,353.465 67.8279,348.798 65.5,343.5C 64.4886,339.888 64.3219,336.221 65,332.5C 65.414,332.043 65.914,331.709 66.5,331.5C 69.4091,334.577 72.7424,337.077 76.5,339C 82.7482,339.188 88.9149,339.688 95,340.5C 96.4869,355.865 89.9869,361.531 75.5,357.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#afafaf" d="M 65.5,343.5 C 67.8279,348.798 71.1612,353.465 75.5,357.5C 75.5,357.833 75.5,358.167 75.5,358.5C 70.6417,355.312 67.3083,350.979 65.5,345.5C 65.5,344.833 65.5,344.167 65.5,343.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#ededed" d="M 407.5,398.5 C 409.167,398.5 410.833,398.5 412.5,398.5C 411.966,404.499 411.299,410.499 410.5,416.5C 402.406,414.736 396.739,410.069 393.5,402.5C 393.608,401.558 393.941,400.725 394.5,400C 399.019,399.825 403.353,399.325 407.5,398.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8e8e8e" d="M 59.5,419.5 C 59.2053,421.735 59.5386,423.735 60.5,425.5C 60.6068,427.379 60.1068,427.712 59,426.5C 58.2042,423.961 58.3709,421.628 59.5,419.5 Z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.6 KiB |
@@ -1 +1 @@
|
||||
<svg id="logosandtypes_com" data-name="logosandtypes com" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150"><defs><style>.cls-1{fill:none;}.cls-2{fill:#e31937;}</style></defs><g id="Layer_2" data-name="Layer 2"><path id="Layer_3" data-name="Layer 3" class="cls-1" d="M0,0H150V150H0Z" transform="translate(0 0)"/></g><rect class="cls-2" x="13.34" y="14.37" width="15.01" height="123.08"/><rect class="cls-2" x="122.92" y="14.37" width="15.01" height="123.08"/><rect class="cls-2" x="43.36" y="54.9" width="64.54" height="15.01"/><rect class="cls-2" x="43.36" y="83.42" width="64.54" height="15.01"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" fill="#e31937" xmlns:v="https://vecta.io/nano"><path d="M13.34 14.37h15.01v123.08H13.34zm109.58 0h15.01v123.08h-15.01zM43.36 54.9h64.54v15.01H43.36zm0 28.52h64.54v15.01H43.36z"/></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 611 B After Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 386 KiB After Width: | Height: | Size: 316 B |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 959 B |
|
Before Width: | Height: | Size: 523 KiB After Width: | Height: | Size: 735 B |
38
auth/assets/custom-icons/icons/nucommunity.svg
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="900px" height="900px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:1" fill="#fefefe" d="M -0.5,-0.5 C 299.5,-0.5 599.5,-0.5 899.5,-0.5C 899.5,299.5 899.5,599.5 899.5,899.5C 599.5,899.5 299.5,899.5 -0.5,899.5C -0.5,599.5 -0.5,299.5 -0.5,-0.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e0a5fc" d="M 297.5,264.5 C 309.66,263.34 321.993,263.173 334.5,264C 337.457,264.279 340.123,265.113 342.5,266.5C 327.57,264.717 312.57,264.051 297.5,264.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8f02d8" d="M 297.5,264.5 C 312.57,264.051 327.57,264.717 342.5,266.5C 369.173,272.584 390.673,286.584 407,308.5C 421.104,329.299 429.604,352.299 432.5,377.5C 432.334,383.509 432.501,389.509 433,395.5C 433.21,397.058 433.71,398.391 434.5,399.5C 434.5,406.5 434.5,413.5 434.5,420.5C 434.5,421.5 434.5,422.5 434.5,423.5C 433.71,422.391 433.21,421.058 433,419.5C 432.5,487.833 432.333,556.166 432.5,624.5C 404.167,624.5 375.833,624.5 347.5,624.5C 347.832,575.997 347.499,527.664 346.5,479.5C 346.829,464.99 346.496,450.657 345.5,436.5C 347.595,406.902 342.095,378.902 329,352.5C 307.252,317.035 275.419,299.368 233.5,299.5C 233.5,299.167 233.5,298.833 233.5,298.5C 250.906,279.797 272.24,268.463 297.5,264.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e2aefc" d="M 464.5,272.5 C 494.329,271.502 524.329,271.169 554.5,271.5C 554.5,330.167 554.5,388.833 554.5,447.5C 554.5,452.833 554.5,458.167 554.5,463.5C 553.501,400.002 553.168,336.336 553.5,272.5C 523.833,272.5 494.167,272.5 464.5,272.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#c47ceb" d="M 789.5,272.5 C 759.662,272.169 729.995,272.502 700.5,273.5C 700.667,355.501 700.5,437.501 700,519.5C 699.819,522.695 699.319,525.695 698.5,528.5C 699.467,442.842 699.801,357.175 699.5,271.5C 729.671,271.169 759.671,271.502 789.5,272.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#f9fff3" d="M 790.5,489.5 C 790.5,417.167 790.5,344.833 790.5,272.5C 791.341,271.991 791.841,272.657 792,274.5C 792.667,345.167 792.667,415.833 792,486.5C 791.667,489.5 791.333,492.5 791,495.5C 790.505,493.527 790.338,491.527 790.5,489.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fedffe" d="M 789.5,272.5 C 789.833,272.5 790.167,272.5 790.5,272.5C 790.5,344.833 790.5,417.167 790.5,489.5C 789.833,492.167 789.167,494.833 788.5,497.5C 789.469,422.51 789.802,347.51 789.5,272.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#eb99fb" d="M 464.5,272.5 C 464.168,339.002 464.501,405.335 465.5,471.5C 465.5,480.5 465.5,489.5 465.5,498.5C 464.672,492.347 464.172,486.013 464,479.5C 463.168,410.332 463.335,341.332 464.5,272.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8113b9" d="M 464.5,272.5 C 494.167,272.5 523.833,272.5 553.5,272.5C 553.168,336.336 553.501,400.002 554.5,463.5C 554.334,472.173 554.5,480.84 555,489.5C 555.183,492.365 555.683,495.031 556.5,497.5C 557.067,504.237 558.067,510.904 559.5,517.5C 558.069,517.119 557.236,516.119 557,514.5C 555.425,506.905 554.259,499.238 553.5,491.5C 552.5,418.836 552.167,346.17 552.5,273.5C 523.5,273.5 494.5,273.5 465.5,273.5C 465.5,339.5 465.5,405.5 465.5,471.5C 464.501,405.335 464.168,339.002 464.5,272.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8f02d8" d="M 559.5,517.5 C 567.209,549.077 585.209,572.91 613.5,589C 621.878,592.737 630.545,595.571 639.5,597.5C 641.515,598.924 643.848,599.59 646.5,599.5C 652.509,599.701 658.509,600.034 664.5,600.5C 664.833,601.167 665.167,601.833 665.5,602.5C 652.044,616.271 636.044,625.937 617.5,631.5C 613.313,632.213 609.313,633.213 605.5,634.5C 604.167,634.5 602.833,634.5 601.5,634.5C 584.03,635.144 566.696,634.144 549.5,631.5C 522.738,623.576 502.238,607.576 488,583.5C 473.799,557.033 466.299,528.699 465.5,498.5C 465.5,489.5 465.5,480.5 465.5,471.5C 465.5,405.5 465.5,339.5 465.5,273.5C 494.5,273.5 523.5,273.5 552.5,273.5C 552.167,346.17 552.5,418.836 553.5,491.5C 554.259,499.238 555.425,506.905 557,514.5C 557.236,516.119 558.069,517.119 559.5,517.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8f01d8" d="M 700.5,273.5 C 730.005,273.169 759.338,273.502 788.5,274.5C 787.167,309.327 786.5,344.494 786.5,380C 786.5,415.506 787.167,450.673 788.5,485.5C 787.326,491.399 786.659,497.399 786.5,503.5C 786.5,505.167 786.5,506.833 786.5,508.5C 775.375,553.295 747.708,582.629 703.5,596.5C 699.521,596.742 695.854,597.742 692.5,599.5C 684.181,600.124 675.848,600.457 667.5,600.5C 685.44,579.935 695.774,555.935 698.5,528.5C 699.319,525.695 699.819,522.695 700,519.5C 700.5,437.501 700.667,355.501 700.5,273.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#9700e9" d="M 788.5,274.5 C 788.5,344.833 788.5,415.167 788.5,485.5C 787.167,450.673 786.5,415.506 786.5,380C 786.5,344.494 787.167,309.327 788.5,274.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#7c10b7" d="M 700.5,273.5 C 729.995,272.502 759.662,272.169 789.5,272.5C 789.802,347.51 789.469,422.51 788.5,497.5C 787.833,499.5 787.167,501.5 786.5,503.5C 786.659,497.399 787.326,491.399 788.5,485.5C 788.5,415.167 788.5,344.833 788.5,274.5C 759.338,273.502 730.005,273.169 700.5,273.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e0b2f7" d="M 214.5,299.5 C 220.645,298.51 226.978,298.177 233.5,298.5C 233.5,298.833 233.5,299.167 233.5,299.5C 232.833,299.833 232.167,300.167 231.5,300.5C 226.025,299.511 220.358,299.178 214.5,299.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#bb82dc" d="M 203.5,301.5 C 201.485,302.924 199.152,303.59 196.5,303.5C 198.515,302.076 200.848,301.41 203.5,301.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8f01d8" d="M 214.5,299.5 C 220.358,299.178 226.025,299.511 231.5,300.5C 214.94,317.802 205.273,338.469 202.5,362.5C 201.693,366.021 201.026,369.688 200.5,373.5C 199.833,374.5 199.167,375.5 198.5,376.5C 196.503,458.827 195.836,541.493 196.5,624.5C 168.167,624.5 139.833,624.5 111.5,624.5C 111.5,552.833 111.5,481.167 111.5,409.5C 111.5,408.833 111.5,408.167 111.5,407.5C 111.646,403.481 111.979,399.481 112.5,395.5C 113.768,393.095 114.435,390.428 114.5,387.5C 121.985,358.168 138.319,335.001 163.5,318C 173.533,310.984 184.533,306.151 196.5,303.5C 199.152,303.59 201.485,302.924 203.5,301.5C 207.221,301.089 210.888,300.422 214.5,299.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#9500e4" d="M 198.5,376.5 C 198.5,459.833 198.5,543.167 198.5,626.5C 169.147,627.159 140.147,626.492 111.5,624.5C 139.833,624.5 168.167,624.5 196.5,624.5C 195.836,541.493 196.503,458.827 198.5,376.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#7d10b7" d="M 200.5,373.5 C 199.513,458.149 199.18,542.815 199.5,627.5C 169.833,627.5 140.167,627.5 110.5,627.5C 110.167,554.665 110.501,481.998 111.5,409.5C 111.5,481.167 111.5,552.833 111.5,624.5C 140.147,626.492 169.147,627.159 198.5,626.5C 198.5,543.167 198.5,459.833 198.5,376.5C 199.167,375.5 199.833,374.5 200.5,373.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#a456d2" d="M 432.5,377.5 C 434.105,384.603 434.772,391.937 434.5,399.5C 433.71,398.391 433.21,397.058 433,395.5C 432.501,389.509 432.334,383.509 432.5,377.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#d898f7" d="M 114.5,387.5 C 114.435,390.428 113.768,393.095 112.5,395.5C 112.294,392.505 112.96,389.838 114.5,387.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fccbfe" d="M 111.5,407.5 C 111.5,408.167 111.5,408.833 111.5,409.5C 110.501,481.998 110.167,554.665 110.5,627.5C 140.167,627.5 169.833,627.5 199.5,627.5C 169.671,628.498 139.671,628.831 109.5,628.5C 109.333,555.166 109.5,481.833 110,408.5C 110.383,407.944 110.883,407.611 111.5,407.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8313bf" d="M 434.5,420.5 C 435.499,489.331 435.833,558.331 435.5,627.5C 405.833,627.5 376.167,627.5 346.5,627.5C 346.5,578.167 346.5,528.833 346.5,479.5C 347.499,527.664 347.832,575.997 347.5,624.5C 376.147,626.492 405.147,627.159 434.5,626.5C 434.5,558.833 434.5,491.167 434.5,423.5C 434.5,422.5 434.5,421.5 434.5,420.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e6b9fc" d="M 434.5,399.5 C 435.327,404.651 435.827,409.984 436,415.5C 436.832,486.335 436.665,557.001 435.5,627.5C 435.833,558.331 435.499,489.331 434.5,420.5C 434.5,413.5 434.5,406.5 434.5,399.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#c48ee5" d="M 202.5,362.5 C 202.271,369.515 201.771,376.515 201,383.5C 200.833,465.001 200.333,546.334 199.5,627.5C 199.18,542.815 199.513,458.149 200.5,373.5C 201.026,369.688 201.693,366.021 202.5,362.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#9800e9" d="M 434.5,423.5 C 434.5,491.167 434.5,558.833 434.5,626.5C 405.147,627.159 376.147,626.492 347.5,624.5C 375.833,624.5 404.167,624.5 432.5,624.5C 432.333,556.166 432.5,487.833 433,419.5C 433.21,421.058 433.71,422.391 434.5,423.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fde2ff" d="M 554.5,447.5 C 555.97,463.978 556.637,480.645 556.5,497.5C 555.683,495.031 555.183,492.365 555,489.5C 554.5,480.84 554.334,472.173 554.5,463.5C 554.5,458.167 554.5,452.833 554.5,447.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e6b4fd" d="M 788.5,497.5 C 788.749,501.458 788.082,505.124 786.5,508.5C 786.5,506.833 786.5,505.167 786.5,503.5C 787.167,501.5 787.833,499.5 788.5,497.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e6b5fa" d="M 703.5,596.5 C 700.146,598.258 696.479,599.258 692.5,599.5C 695.854,597.742 699.521,596.742 703.5,596.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#d196ef" d="M 639.5,597.5 C 642.152,597.41 644.485,598.076 646.5,599.5C 643.848,599.59 641.515,598.924 639.5,597.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#eebef9" d="M 692.5,599.5 C 683.638,600.905 674.638,601.905 665.5,602.5C 665.167,601.833 664.833,601.167 664.5,600.5C 665.5,600.5 666.5,600.5 667.5,600.5C 675.848,600.457 684.181,600.124 692.5,599.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e8b7fd" d="M 345.5,436.5 C 346.496,450.657 346.829,464.99 346.5,479.5C 346.5,528.833 346.5,578.167 346.5,627.5C 376.167,627.5 405.833,627.5 435.5,627.5C 405.671,628.498 375.671,628.831 345.5,628.5C 345.5,564.5 345.5,500.5 345.5,436.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#eeccfd" d="M 617.5,631.5 C 614.032,634.114 610.032,635.114 605.5,634.5C 609.313,633.213 613.313,632.213 617.5,631.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#902eca" d="M 549.5,631.5 C 566.696,634.144 584.03,635.144 601.5,634.5C 598.375,635.479 595.042,635.813 591.5,635.5C 581.461,635.758 571.461,635.424 561.5,634.5C 557.098,634.692 553.098,633.692 549.5,631.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#e2b3f9" d="M 561.5,634.5 C 571.461,635.424 581.461,635.758 591.5,635.5C 582.009,636.658 572.342,636.825 562.5,636C 561.944,635.617 561.611,635.117 561.5,634.5 Z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 671 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 2.5 KiB |
6
auth/assets/custom-icons/icons/render.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:1" fill="#fefefe" d="M -0.5,-0.5 C 66.1667,-0.5 132.833,-0.5 199.5,-0.5C 199.5,66.1667 199.5,132.833 199.5,199.5C 132.833,199.5 66.1667,199.5 -0.5,199.5C -0.5,132.833 -0.5,66.1667 -0.5,-0.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#0e0e0e" d="M 119.5,47.5 C 133.743,46.0344 143.909,51.701 150,64.5C 154.009,81.9852 147.509,93.4852 130.5,99C 123.167,99.3333 115.833,99.6667 108.5,100C 104.333,101.5 101.5,104.333 100,108.5C 99.5001,122.829 99.3334,137.163 99.5,151.5C 82.1667,151.5 64.8333,151.5 47.5,151.5C 47.5,132.833 47.5,114.167 47.5,95.5C 60.0736,101.213 72.4069,100.713 84.5,94C 88.6667,91.1667 92.1667,87.6667 95,83.5C 97.7515,75.0718 100.752,66.7384 104,58.5C 108.127,53.202 113.294,49.5354 119.5,47.5 Z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
7
auth/assets/custom-icons/icons/samsung.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="2030px" height="2048px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:0.999" fill="#0066ff" d="M 922.5,-0.5 C 984.167,-0.5 1045.83,-0.5 1107.5,-0.5C 1183.34,2.62698 1259.01,9.46031 1334.5,20C 1435.99,34.2851 1532.99,63.2851 1625.5,107C 1686.68,137.224 1742.68,174.891 1793.5,220C 1851.84,280.056 1898,348.556 1932,425.5C 1968.98,509.727 1994.31,597.394 2008,688.5C 2018.55,761.657 2025.72,834.99 2029.5,908.5C 2029.5,984.833 2029.5,1061.17 2029.5,1137.5C 2025.59,1213.37 2018.09,1289.04 2007,1364.5C 1992.77,1456.52 1966.44,1544.85 1928,1629.5C 1897.8,1694.64 1859.13,1753.97 1812,1807.5C 1763.29,1856.1 1708.46,1896.26 1647.5,1928C 1544.73,1980.25 1436.06,2013.59 1321.5,2028C 1239.36,2038.97 1157.03,2045.47 1074.5,2047.5C 1060.5,2047.5 1046.5,2047.5 1032.5,2047.5C 1020.83,2046.17 1009.17,2046.17 997.5,2047.5C 983.5,2047.5 969.5,2047.5 955.5,2047.5C 872.975,2045.46 790.642,2038.96 708.5,2028C 606.933,2014.94 509.599,1987.28 416.5,1945C 347.284,1912.42 284.617,1870.42 228.5,1819C 172.903,1758.37 128.403,1690.2 95,1614.5C 60.5996,1534.57 36.5996,1451.57 23,1365.5C 10.7368,1283.1 2.90342,1200.43 -0.5,1117.5C -0.5,1054.5 -0.5,991.5 -0.5,928.5C 2.77579,849.967 9.94246,771.634 21,693.5C 36.75,581.253 70.75,474.92 123,374.5C 154.057,316.905 192.557,264.739 238.5,218C 316.452,150.162 404.785,99.4952 503.5,66C 559.947,46.805 617.613,32.4717 676.5,23C 758.221,10.617 840.221,2.78365 922.5,-0.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fefeff" d="M 626.5,1312.5 C 626.5,1276.83 626.5,1241.17 626.5,1205.5C 722.5,1205.5 818.5,1205.5 914.5,1205.5C 914.333,1244.17 914.5,1282.83 915,1321.5C 919.897,1362.39 941.73,1389.55 980.5,1403C 1004.93,1409.12 1029.59,1410.12 1054.5,1406C 1094.33,1398.51 1118.83,1375.01 1128,1335.5C 1139.64,1293.91 1132.31,1256.24 1106,1222.5C 1094.47,1209.3 1081.97,1197.13 1068.5,1186C 1051.72,1173.22 1034.38,1161.22 1016.5,1150C 961.491,1118.16 906.158,1086.83 850.5,1056C 810.408,1032.63 772.408,1006.29 736.5,977C 708.562,953.08 685.062,925.58 666,894.5C 645.646,856.764 634.646,816.431 633,773.5C 624.333,602.57 702.833,497.07 868.5,457C 927.844,444.215 987.844,439.548 1048.5,443C 1106.86,444.281 1163.52,454.614 1218.5,474C 1318.44,513.324 1371.28,586.824 1377,694.5C 1377.5,726.832 1377.67,759.165 1377.5,791.5C 1288.17,791.5 1198.83,791.5 1109.5,791.5C 1109.67,765.165 1109.5,738.831 1109,712.5C 1103.68,665.514 1077.85,637.347 1031.5,628C 1000.82,622.223 972.154,627.223 945.5,643C 926.118,658.253 914.285,678.086 910,702.5C 905.639,729.545 909.639,755.212 922,779.5C 936.918,800.419 955.085,817.919 976.5,832C 993.234,843.062 1010.23,853.729 1027.5,864C 1086.31,895.238 1144.65,927.238 1202.5,960C 1251.24,988.047 1295.4,1022.21 1335,1062.5C 1363.36,1092.86 1383.19,1128.19 1394.5,1168.5C 1403.09,1210.74 1405.93,1253.41 1403,1296.5C 1401.52,1447.37 1328.36,1543.2 1183.5,1584C 1116.22,1600.81 1047.89,1607.14 978.5,1603C 920.733,1601.37 864.733,1590.71 810.5,1571C 693.944,1524.55 632.61,1438.38 626.5,1312.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#8eb7ff" d="M 914.5,1205.5 C 818.5,1205.5 722.5,1205.5 626.5,1205.5C 626.5,1241.17 626.5,1276.83 626.5,1312.5C 625.502,1276.67 625.168,1240.67 625.5,1204.5C 722.001,1204.17 818.335,1204.5 914.5,1205.5 Z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 389 KiB After Width: | Height: | Size: 429 B |
8
auth/assets/custom-icons/icons/twitch.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="2400px" height="2800px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g><path style="opacity:1" fill="#9146ff" d="M 498.5,-0.5 C 1132.17,-0.5 1765.83,-0.5 2399.5,-0.5C 2399.5,466.5 2399.5,933.5 2399.5,1400.5C 2099.7,1699.8 1800.03,1999.3 1500.5,2299C 1366.83,2299.33 1233.17,2299.67 1099.5,2300C 932.965,2466.37 766.632,2632.87 600.5,2799.5C 600.167,2799.5 599.833,2799.5 599.5,2799.5C 599.5,2632.83 599.5,2466.17 599.5,2299.5C 399.5,2299.5 199.5,2299.5 -0.5,2299.5C -0.5,1699.17 -0.5,1098.83 -0.5,498.5C 166.167,332.5 332.5,166.167 498.5,-0.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#fefffe" d="M 599.5,199.5 C 1132.83,199.5 1666.17,199.5 2199.5,199.5C 2199.67,566.167 2199.5,932.833 2199,1299.5C 2065.83,1432.67 1932.67,1565.83 1799.5,1699C 1665.83,1699.33 1532.17,1699.67 1398.5,1700C 1282.33,1816.17 1166.17,1932.33 1050,2048.5C 1049.5,1932.17 1049.33,1815.83 1049.5,1699.5C 899.5,1699.5 749.5,1699.5 599.5,1699.5C 599.5,1199.5 599.5,699.5 599.5,199.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#9146ff" d="M 1149.5,549.5 C 1216.17,549.5 1282.83,549.5 1349.5,549.5C 1349.5,749.5 1349.5,949.5 1349.5,1149.5C 1282.83,1149.5 1216.17,1149.5 1149.5,1149.5C 1149.5,949.5 1149.5,749.5 1149.5,549.5 Z"/></g>
|
||||
<g><path style="opacity:1" fill="#9146ff" d="M 1699.5,549.5 C 1766.17,549.5 1832.83,549.5 1899.5,549.5C 1899.5,749.5 1899.5,949.5 1899.5,1149.5C 1832.83,1149.5 1766.17,1149.5 1699.5,1149.5C 1699.5,949.5 1699.5,749.5 1699.5,549.5 Z"/></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -7,6 +7,15 @@ If you would like to add your own custom icon, please open a pull-request with
|
||||
the relevant SVG placed within `assets/custom-icons/icons` and add the
|
||||
corresponding entry within `assets/custom-icons/_data/custom-icons.json`.
|
||||
|
||||
Please be careful to upload small and optimized icon files. If your icon file
|
||||
is over 50KB, it is likely not optimized.
|
||||
|
||||
Note that the correspondence between the icon and the issuer is based on the name
|
||||
of the issuer provided by the user, excluding spaces. Only the text before the
|
||||
first dot "." or left parentheses "(" will be used for icon matching.
|
||||
e.g. Issuer name provided: "github.com (Main account)" - Then "github" will be
|
||||
used for matching.
|
||||
|
||||
This JSON file contains the following attributes:
|
||||
|
||||
| Attribute | Usecase | Required |
|
||||
|
||||
@@ -81,12 +81,12 @@ PODS:
|
||||
- qr_code_scanner (0.2.0):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
- ReachabilitySwift (5.2.2)
|
||||
- ReachabilitySwift (5.2.3)
|
||||
- SDWebImage (5.19.2):
|
||||
- SDWebImage/Core (= 5.19.2)
|
||||
- SDWebImage/Core (5.19.2)
|
||||
- Sentry/HybridSDK (8.25.0)
|
||||
- sentry_flutter (7.20.1):
|
||||
- sentry_flutter (7.20.2):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.25.0)
|
||||
@@ -100,18 +100,21 @@ PODS:
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (3.45.3+1)":
|
||||
- "sqlite3/common (= 3.45.3+1)"
|
||||
- "sqlite3/common (3.45.3+1)"
|
||||
- "sqlite3/fts5 (3.45.3+1)":
|
||||
- "sqlite3 (3.46.0+1)":
|
||||
- "sqlite3/common (= 3.46.0+1)"
|
||||
- "sqlite3/common (3.46.0+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/perf-threadsafe (3.45.3+1)":
|
||||
- "sqlite3/fts5 (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.45.3+1)":
|
||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- Flutter
|
||||
- "sqlite3 (~> 3.45.3+1)"
|
||||
- "sqlite3 (~> 3.46.0+1)"
|
||||
- sqlite3/dbstatvtab
|
||||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
@@ -233,29 +236,29 @@ SPEC CHECKSUMS:
|
||||
flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
||||
fluttertoast: 9f2f8e81bb5ce18facb9748d7855bf5a756fe3db
|
||||
local_auth_darwin: c7e464000a6a89e952235699e32b329457608d98
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
|
||||
local_auth_darwin: 4d56c90c2683319835a61274b57620df9c4520ab
|
||||
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
|
||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
||||
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||
ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149
|
||||
ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979
|
||||
SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a
|
||||
Sentry: cd86fc55628f5b7c572cabe66cc8f95a9d2f165a
|
||||
sentry_flutter: 4cb24c1055c556d7b27262ab2e179d1e5a0b9b0c
|
||||
sentry_flutter: 0cf2507eb90ff7a6aa3304e900dd7f08edbbefdf
|
||||
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sodium_libs: 1faae17af662384acbd13e41867a0008cd2e2318
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqlite3: 02d1f07eaaa01f80a1c16b4b31dfcbb3345ee01a
|
||||
sqlite3_flutter_libs: 9bfe005308998aeca155330bbc2ea6dddf834a3b
|
||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
||||
sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
|
||||
PODFILE CHECKSUM: b4e3a7eabb03395b66e81fc061789f61526ee6bb
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:ente_auth/events/signed_out_event.dart';
|
||||
import "package:ente_auth/l10n/l10n.dart";
|
||||
import 'package:ente_auth/locale.dart';
|
||||
import "package:ente_auth/onboarding/view/onboarding_page.dart";
|
||||
import 'package:ente_auth/services/authenticator_service.dart';
|
||||
import 'package:ente_auth/services/update_service.dart';
|
||||
import 'package:ente_auth/services/user_service.dart';
|
||||
import 'package:ente_auth/services/window_listener_service.dart';
|
||||
@@ -34,7 +35,8 @@ class App extends StatefulWidget {
|
||||
State<App> createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> with WindowListener, TrayListener {
|
||||
class _AppState extends State<App>
|
||||
with WindowListener, TrayListener, WidgetsBindingObserver {
|
||||
late StreamSubscription<SignedOutEvent> _signedOutEvent;
|
||||
late StreamSubscription<SignedInEvent> _signedInEvent;
|
||||
Locale? locale;
|
||||
@@ -56,6 +58,7 @@ class _AppState extends State<App> with WindowListener, TrayListener {
|
||||
void initState() {
|
||||
initWindowManager();
|
||||
initTrayManager();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
_signedOutEvent = Bus.instance.on<SignedOutEvent>().listen((event) {
|
||||
if (mounted) {
|
||||
@@ -98,6 +101,15 @@ class _AppState extends State<App> with WindowListener, TrayListener {
|
||||
_signedInEvent.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
if (Configuration.instance.hasConfiguredAccount()) {
|
||||
AuthenticatorService.instance.onlineSync().ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (Platform.isAndroid || kDebugMode) {
|
||||
|
||||
71
auth/lib/core/win_http_client.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
/*
|
||||
Reference from
|
||||
https://github.com/realm/realm-dart/blob/main/packages/realm_dart/lib/src/handles/native/default_client.dart
|
||||
https://github.com/realm/realm-dart/pull/1378
|
||||
*/
|
||||
HttpClient windowsHttpClient() {
|
||||
final logger = Logger("WindowsHttpClient");
|
||||
const isrgRootX1CertPEM = // The root certificate used by lets encrypt
|
||||
'''
|
||||
subject=CN=ISRG Root X1,O=Internet Security Research Group,C=US
|
||||
issuer=CN=DST Root CA X3,O=Digital Signature Trust Co.
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
|
||||
ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
|
||||
wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
|
||||
LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
|
||||
4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
|
||||
bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
|
||||
sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
|
||||
Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
|
||||
FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
|
||||
SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
|
||||
PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
|
||||
TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
|
||||
SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
|
||||
c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
|
||||
+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
|
||||
ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
|
||||
b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
|
||||
U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
|
||||
5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
|
||||
9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
|
||||
WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
|
||||
he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
|
||||
Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
|
||||
-----END CERTIFICATE-----''';
|
||||
|
||||
if (Platform.isWindows) {
|
||||
final context = SecurityContext(withTrustedRoots: true);
|
||||
try {
|
||||
logger.info('Adding certificate to trusted certificates');
|
||||
context.setTrustedCertificatesBytes(
|
||||
const AsciiEncoder().convert(isrgRootX1CertPEM),
|
||||
);
|
||||
logger.info("Certificate added to trusted certificates");
|
||||
return HttpClient(context: context);
|
||||
} on TlsException catch (e) {
|
||||
logger.warning(
|
||||
"Error adding certificate to trusted certificates: ${e.osError?.message}",
|
||||
);
|
||||
// certificate is already trusted. Nothing to do here
|
||||
if (e.osError?.message.contains("CERT_ALREADY_IN_HASH_TABLE") != true) {
|
||||
rethrow;
|
||||
} else {
|
||||
return HttpClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw UnsupportedError("This platform is not supported");
|
||||
}
|
||||
@@ -263,12 +263,15 @@
|
||||
"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!",
|
||||
"privacy": "Datenschutz",
|
||||
"terms": "Bestimmungen",
|
||||
"checkForUpdates": "Auf Updates prüfen",
|
||||
"checkStatus": "Status überprüfen",
|
||||
"downloadUpdate": "Herunterladen",
|
||||
"criticalUpdateAvailable": "Kritische neue Aktualisierung ist verfügbar",
|
||||
"updateAvailable": "Aktualisierung verfügbar",
|
||||
@@ -417,6 +420,9 @@
|
||||
"waitingForBrowserRequest": "Warten auf Browseranfrage...",
|
||||
"waitingForVerification": "Warte auf Bestätigung...",
|
||||
"passkey": "Passkey",
|
||||
"passKeyPendingVerification": "Verifizierung steht noch aus",
|
||||
"loginSessionExpired": "Sitzung abgelaufen",
|
||||
"loginSessionExpiredDetails": "Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",
|
||||
"developerSettingsWarning": "Sind Sie sicher, dass Sie die Entwicklereinstellungen ändern möchten?",
|
||||
"developerSettings": "Entwicklereinstellungen",
|
||||
"serverEndpoint": "Server Endpunkt",
|
||||
|
||||
@@ -263,6 +263,8 @@
|
||||
"exportLogs": "Export logs",
|
||||
"enterYourRecoveryKey": "Enter your recovery key",
|
||||
"tempErrorContactSupportIfPersists": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
|
||||
"networkHostLookUpErr": "Unable to connect to Ente, please check your network settings and contact support if the error persists.",
|
||||
"networkConnectionRefusedErr": "Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.",
|
||||
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
|
||||
"about": "About",
|
||||
"weAreOpenSource": "We are open source!",
|
||||
|
||||
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,12 +263,15 @@
|
||||
"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!",
|
||||
"privacy": "Privacy",
|
||||
"terms": "Termini",
|
||||
"checkForUpdates": "Controlla aggiornamenti",
|
||||
"checkStatus": "Verifica stato",
|
||||
"downloadUpdate": "Scarica",
|
||||
"criticalUpdateAvailable": "Un aggiornamento importante è disponibile",
|
||||
"updateAvailable": "Aggiornamento disponibile",
|
||||
@@ -417,6 +420,9 @@
|
||||
"waitingForBrowserRequest": "In attesa della richiesta del browser...",
|
||||
"waitingForVerification": "In attesa di verifica...",
|
||||
"passkey": "Passkey",
|
||||
"passKeyPendingVerification": "La verifica è ancora in corso",
|
||||
"loginSessionExpired": "Sessione scaduta",
|
||||
"loginSessionExpiredDetails": "La sessione è scaduta. Si prega di accedere nuovamente.",
|
||||
"developerSettingsWarning": "Siete sicuri di voler modificare le impostazioni sviluppatore?",
|
||||
"developerSettings": "Impostazioni sviluppatore",
|
||||
"serverEndpoint": "Endpoint del server",
|
||||
|
||||
@@ -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": "サーバーエンドポイント",
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
"privacy": "Privacy",
|
||||
"terms": "Voorwaarden",
|
||||
"checkForUpdates": "Controleer op updates",
|
||||
"checkStatus": "Status controleren",
|
||||
"downloadUpdate": "Downloaden",
|
||||
"criticalUpdateAvailable": "Belangrijke update beschikbaar",
|
||||
"updateAvailable": "Update beschikbaar",
|
||||
@@ -417,6 +418,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,7 @@
|
||||
"codeIssuerHint": "Wydawca",
|
||||
"codeSecretKeyHint": "Tajny klucz",
|
||||
"codeAccountHint": "Konto (ty@domena.com)",
|
||||
"accountKeyType": "Rodzaj klucza",
|
||||
"sessionExpired": "Sesja wygasła",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -77,11 +78,14 @@
|
||||
"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.",
|
||||
"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.",
|
||||
"exportCodes": "Eksportuj kody",
|
||||
@@ -107,12 +111,14 @@
|
||||
"copied": "Skopiowano",
|
||||
"pleaseTryAgain": "Proszę spróbować ponownie",
|
||||
"existingUser": "Istniejący użytkownik",
|
||||
"newUser": "Nowy 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_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?",
|
||||
@@ -143,6 +149,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"invalidQRCode": "Nieprawidłowy kod QR",
|
||||
"noRecoveryKeyTitle": "Brak klucza odzyskiwania?",
|
||||
"enterEmailHint": "Wprowadź adres e-mail",
|
||||
"invalidEmailTitle": "Nieprawidłowy adres e-mail",
|
||||
@@ -333,10 +340,18 @@
|
||||
"deleteCodeAuthMessage": "Uwierzytelnij, aby usunąć kod",
|
||||
"showQRAuthMessage": "Uwierzytelnij, aby pokazać kod QR",
|
||||
"confirmAccountDeleteTitle": "Potwierdź usunięcie konta",
|
||||
"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 +360,38 @@
|
||||
"@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."
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"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)",
|
||||
"recoveryKeySaved": "Klucz odzyskiwania zapisany w folderze Pobrane!",
|
||||
"waitingForVerification": "Oczekiwanie na weryfikację...",
|
||||
"developerSettings": "Ustawienia deweloperskie"
|
||||
"loginSessionExpired": "Sesja wygasła",
|
||||
"loginSessionExpiredDetails": "Twoja sesja wygasła. Zaloguj się ponownie.",
|
||||
"developerSettingsWarning": "Czy na pewno chcesz zmodyfikować ustawienia programisty?",
|
||||
"developerSettings": "Ustawienia deweloperskie",
|
||||
"customEndpoint": "Połączono z {endpoint}",
|
||||
"pinText": "Przypnij",
|
||||
"unpinText": "Odepnij",
|
||||
"pinnedCodeMessage": "Przypięto {code}",
|
||||
"unpinnedCodeMessage": "Odpięto {code}",
|
||||
"create": "Utwórz",
|
||||
"deleteTagTitle": "Usunąć etykietę?",
|
||||
"somethingWentWrongParsingCode": "Nie udało się przetworzyć kodów {x}.",
|
||||
"updateNotAvailable": "Aktualizacja jest niedostępna"
|
||||
}
|
||||
@@ -263,12 +263,15 @@
|
||||
"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!",
|
||||
"privacy": "Privacidade",
|
||||
"terms": "Termos",
|
||||
"checkForUpdates": "Verificar por atualizações",
|
||||
"checkStatus": "Verificar status",
|
||||
"downloadUpdate": "Baixar",
|
||||
"criticalUpdateAvailable": "Atualização crítica disponível",
|
||||
"updateAvailable": "Atualização disponível",
|
||||
@@ -417,6 +420,9 @@
|
||||
"waitingForBrowserRequest": "Aguardando solicitação do navegador...",
|
||||
"waitingForVerification": "Esperando por verificação...",
|
||||
"passkey": "Senha-mestra",
|
||||
"passKeyPendingVerification": "A verificação ainda está pendente",
|
||||
"loginSessionExpired": "Sessão expirada",
|
||||
"loginSessionExpiredDetails": "Sua sessão expirou. Por favor, entre novamente.",
|
||||
"developerSettingsWarning": "Tem certeza de que deseja modificar as configurações de Desenvolvedor?",
|
||||
"developerSettings": "Configurações de desenvolvedor",
|
||||
"serverEndpoint": "Endpoint do servidor",
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
"privacy": "Конфиденциальность",
|
||||
"terms": "Условия использования",
|
||||
"checkForUpdates": "Проверить наличие обновлений",
|
||||
"checkStatus": "Проверить статус",
|
||||
"downloadUpdate": "Скачать",
|
||||
"criticalUpdateAvailable": "Доступно критическое обновление",
|
||||
"updateAvailable": "Доступно обновление",
|
||||
@@ -417,6 +418,9 @@
|
||||
"waitingForBrowserRequest": "Ожидание запроса браузера...",
|
||||
"waitingForVerification": "Ожидание подтверждения...",
|
||||
"passkey": "Ключ",
|
||||
"passKeyPendingVerification": "Верификация еще не завершена",
|
||||
"loginSessionExpired": "Сессия недействительна",
|
||||
"loginSessionExpiredDetails": "Сессия истекла. Войдите снова.",
|
||||
"developerSettingsWarning": "Вы уверены, что хотите изменить настройки разработчика?",
|
||||
"developerSettings": "Настройки разработчика",
|
||||
"serverEndpoint": "Конечная точка сервера",
|
||||
|
||||
@@ -159,5 +159,6 @@
|
||||
"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": "Ingen internetanslutning",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Kontrollera din internetanslutning och försök igen."
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Kontrollera din internetanslutning och försök igen.",
|
||||
"loginSessionExpiredDetails": "Din session har upphört. Logga in igen."
|
||||
}
|
||||
@@ -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?",
|
||||
|
||||
@@ -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": "服务器端点",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -49,7 +49,7 @@ class PasskeyService {
|
||||
);
|
||||
} catch (e) {
|
||||
Logger('PasskeyService').severe("failed to open passkey page", e);
|
||||
showGenericErrorDialog(context: context).ignore();
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ class UserService {
|
||||
);
|
||||
return;
|
||||
}
|
||||
unawaited(showGenericErrorDialog(context: context));
|
||||
unawaited(showGenericErrorDialog(context: context, error: null));
|
||||
} on DioException catch (e) {
|
||||
await dialog.hide();
|
||||
_logger.info(e);
|
||||
@@ -114,12 +114,12 @@ class UserService {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
unawaited(showGenericErrorDialog(context: context));
|
||||
unawaited(showGenericErrorDialog(context: context, error: e));
|
||||
}
|
||||
} catch (e) {
|
||||
await dialog.hide();
|
||||
_logger.severe(e);
|
||||
unawaited(showGenericErrorDialog(context: context));
|
||||
unawaited(showGenericErrorDialog(context: context, error: e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,11 @@ class UserService {
|
||||
return userDetails;
|
||||
} catch (e) {
|
||||
_logger.warning("Failed to fetch", e);
|
||||
rethrow;
|
||||
if (e is DioException && e.response?.statusCode == 401) {
|
||||
throw UnauthorizedError();
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,11 +217,17 @@ class UserService {
|
||||
}
|
||||
} catch (e) {
|
||||
_logger.severe(e);
|
||||
// check if token is already invalid
|
||||
if (e is DioException && e.response?.statusCode == 401) {
|
||||
await Configuration.instance.logout();
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
return;
|
||||
}
|
||||
//This future is for waiting for the dialog from which logout() is called
|
||||
//to close and only then to show the error dialog.
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 150),
|
||||
() => showGenericErrorDialog(context: context),
|
||||
() => showGenericErrorDialog(context: context, error: e),
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
@@ -238,7 +248,10 @@ class UserService {
|
||||
}
|
||||
} catch (e) {
|
||||
_logger.severe(e);
|
||||
await showGenericErrorDialog(context: context);
|
||||
await showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,51 +3,64 @@ import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/store/authenticator_db.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
bool showingLogoutDialog = false;
|
||||
Future<void> autoLogoutAlert(BuildContext context) async {
|
||||
final l10n = context.l10n;
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: Text(l10n.sessionExpired),
|
||||
content: Text(l10n.pleaseLoginAgain),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.ok,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
if (showingLogoutDialog) {
|
||||
debugPrint("Ignore event as already logging out");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
showingLogoutDialog = true;
|
||||
final l10n = context.l10n;
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: Text(l10n.sessionExpired),
|
||||
content: Text(l10n.pleaseLoginAgain),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
l10n.ok,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
int pendingSyncCount =
|
||||
await AuthenticatorDB.instance.getNeedSyncCount();
|
||||
if (pendingSyncCount > 0) {
|
||||
// ignore: unawaited_futures
|
||||
showChoiceActionSheet(
|
||||
context,
|
||||
title: l10n.pendingSyncs,
|
||||
body: l10n.pendingSyncsWarningBody,
|
||||
firstButtonLabel: context.l10n.yesLogout,
|
||||
isCritical: true,
|
||||
firstButtonOnTap: () async {
|
||||
await _logout(context, l10n);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _logout(context, l10n);
|
||||
}
|
||||
},
|
||||
),
|
||||
onPressed: () async {
|
||||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
int pendingSyncCount =
|
||||
await AuthenticatorDB.instance.getNeedSyncCount();
|
||||
if (pendingSyncCount > 0) {
|
||||
// ignore: unawaited_futures
|
||||
showChoiceActionSheet(
|
||||
context,
|
||||
title: l10n.pendingSyncs,
|
||||
body: l10n.pendingSyncsWarningBody,
|
||||
firstButtonLabel: context.l10n.yesLogout,
|
||||
isCritical: true,
|
||||
firstButtonOnTap: () async {
|
||||
await _logout(context, l10n);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _logout(context, l10n);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
await showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
],
|
||||
);
|
||||
await showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
Logger("LogoutDialog").severe('failed to process sign out action', e);
|
||||
} finally {
|
||||
showingLogoutDialog = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _logout(BuildContext context, AppLocalizations l10n) async {
|
||||
|
||||
@@ -412,7 +412,10 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
|
||||
_logger.severe(e, s);
|
||||
await dialog.hide();
|
||||
// ignore: unawaited_futures
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +475,10 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
|
||||
_logger.severe(e, s);
|
||||
await dialog.hide();
|
||||
// ignore: unawaited_futures
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +506,10 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
|
||||
);
|
||||
} else {
|
||||
// ignore: unawaited_futures
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,10 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
|
||||
"Please check your internet connection and try again.",
|
||||
);
|
||||
} else {
|
||||
await showGenericErrorDialog(context: context);
|
||||
await showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -107,7 +110,10 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
|
||||
);
|
||||
} catch (e) {
|
||||
// ignore: unawaited_futures
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +485,10 @@ class _ButtonChildWidgetState extends State<ButtonChildWidget> {
|
||||
} else if (exception != null) {
|
||||
//This is to show the execution was unsuccessful if the dialog is manually
|
||||
//closed before the execution completes.
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: exception,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ class _HomePageState extends State<HomePage> {
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
final TextEditingController _textController = TextEditingController();
|
||||
final FocusNode searchInputFocusNode = FocusNode();
|
||||
final bool _autoFocusSearch =
|
||||
PreferenceService.instance.shouldAutoFocusOnSearchBar();
|
||||
bool _showSearchBox = false;
|
||||
String _searchText = "";
|
||||
List<Code>? _allCodes;
|
||||
@@ -87,18 +88,7 @@ class _HomePageState extends State<HomePage> {
|
||||
_iconsChangedEvent = Bus.instance.on<IconsChangedEvent>().listen((event) {
|
||||
setState(() {});
|
||||
});
|
||||
_showSearchBox = PreferenceService.instance.shouldAutoFocusOnSearchBar();
|
||||
if (_showSearchBox) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) {
|
||||
// https://github.com/flutter/flutter/issues/20706#issuecomment-646328652
|
||||
FocusScope.of(context).unfocus();
|
||||
Timer(const Duration(milliseconds: 1), () {
|
||||
FocusScope.of(context).requestFocus(searchInputFocusNode);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
_showSearchBox = _autoFocusSearch;
|
||||
}
|
||||
|
||||
void _loadCodes() {
|
||||
@@ -240,8 +230,7 @@ class _HomePageState extends State<HomePage> {
|
||||
: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
focusNode: searchInputFocusNode,
|
||||
autofocus: _searchText.isEmpty,
|
||||
autofocus: _autoFocusSearch,
|
||||
controller: _textController,
|
||||
onChanged: (val) {
|
||||
_searchText = val;
|
||||
@@ -460,7 +449,10 @@ class _HomePageState extends State<HomePage> {
|
||||
CodeStore.instance.addCode(newCode);
|
||||
_focusNewCode(newCode);
|
||||
} catch (e, s) {
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
_logger.severe("error while handling deeplink", e, s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class _PasskeyPageState extends State<PasskeyPage> {
|
||||
return;
|
||||
} catch (e, s) {
|
||||
_logger.severe("failed to check status", e, s);
|
||||
showGenericErrorDialog(context: context).ignore();
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
return;
|
||||
}
|
||||
await UserService.instance.onPassKeyVerified(context, response);
|
||||
@@ -111,7 +111,7 @@ class _PasskeyPageState extends State<PasskeyPage> {
|
||||
}
|
||||
} catch (e, s) {
|
||||
_logger.severe('passKey: failed to handle deeplink', e, s);
|
||||
showGenericErrorDialog(context: context).ignore();
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ class _PasskeyPageState extends State<PasskeyPage> {
|
||||
await checkStatus();
|
||||
} catch (e) {
|
||||
debugPrint('failed to check status %e');
|
||||
showGenericErrorDialog(context: context).ignore();
|
||||
showGenericErrorDialog(context: context, error: e).ignore();
|
||||
}
|
||||
},
|
||||
shouldSurfaceExecutionStates: true,
|
||||
|
||||
@@ -111,7 +111,10 @@ class AccountSectionWidget extends StatelessWidget {
|
||||
CryptoUtil.bin2hex(Configuration.instance.getRecoveryKey());
|
||||
} catch (e) {
|
||||
// ignore: unawaited_futures
|
||||
showGenericErrorDialog(context: context);
|
||||
showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
return;
|
||||
}
|
||||
// ignore: unawaited_futures
|
||||
|
||||
@@ -182,7 +182,10 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
||||
PasskeyService.instance.openPasskeyPage(buildContext).ignore();
|
||||
} catch (e, s) {
|
||||
_logger.severe("failed to open passkey page", e, s);
|
||||
await showGenericErrorDialog(context: context);
|
||||
await showGenericErrorDialog(
|
||||
context: context,
|
||||
error: e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ import 'package:ente_auth/ui/components/components_constants.dart';
|
||||
import 'package:ente_auth/ui/components/dialog_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_result.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_type.dart';
|
||||
import 'package:ente_auth/utils/email_util.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef DialogBuilder = DialogWidget Function(BuildContext context);
|
||||
@@ -69,22 +71,97 @@ Future<ButtonResult?> showErrorDialogForException({
|
||||
);
|
||||
}
|
||||
|
||||
String parseErrorForUI(
|
||||
BuildContext context,
|
||||
String genericError, {
|
||||
Object? error,
|
||||
bool surfaceError = kDebugMode,
|
||||
}) {
|
||||
try {
|
||||
if (error == null) {
|
||||
return genericError;
|
||||
}
|
||||
if (error is DioException) {
|
||||
final DioException dioError = error;
|
||||
if (dioError.type == DioExceptionType.unknown) {
|
||||
if (dioError.error.toString().contains('Failed host lookup')) {
|
||||
return context.l10n.networkHostLookUpErr;
|
||||
} else if (dioError.error.toString().contains('SocketException')) {
|
||||
return context.l10n.networkConnectionRefusedErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return generic error if the user is not internal and the error is not in debug mode
|
||||
if (!kDebugMode) {
|
||||
return genericError;
|
||||
}
|
||||
String errorInfo = "";
|
||||
if (error is DioException) {
|
||||
final DioException dioError = error;
|
||||
if (dioError.type == DioExceptionType.badResponse) {
|
||||
if (dioError.response?.data["code"] != null) {
|
||||
errorInfo = "Reason: " + dioError.response!.data["code"];
|
||||
} else {
|
||||
errorInfo = "Reason: " + dioError.response!.data.toString();
|
||||
}
|
||||
} else if (dioError.type == DioExceptionType.unknown) {
|
||||
errorInfo = "Reason: " + dioError.error.toString();
|
||||
} else {
|
||||
errorInfo = "Reason: " + dioError.type.toString();
|
||||
}
|
||||
} else {
|
||||
if (kDebugMode) {
|
||||
errorInfo = error.toString();
|
||||
} else {
|
||||
errorInfo = error.toString().split('Source stack')[0];
|
||||
}
|
||||
}
|
||||
if (errorInfo.isNotEmpty) {
|
||||
return "$genericError\n\n$errorInfo";
|
||||
}
|
||||
return genericError;
|
||||
} catch (e) {
|
||||
return genericError;
|
||||
}
|
||||
}
|
||||
|
||||
///Will return null if dismissed by tapping outside
|
||||
Future<ButtonResult?> showGenericErrorDialog({
|
||||
required BuildContext context,
|
||||
bool isDismissible = true,
|
||||
required Object? error,
|
||||
}) async {
|
||||
final errorBody = parseErrorForUI(
|
||||
context,
|
||||
context.l10n.itLooksLikeSomethingWentWrongPleaseRetryAfterSome,
|
||||
error: error,
|
||||
);
|
||||
|
||||
return showDialogWidget(
|
||||
context: context,
|
||||
title: context.l10n.error,
|
||||
icon: Icons.error_outline_outlined,
|
||||
body: context.l10n.itLooksLikeSomethingWentWrongPleaseRetryAfterSome,
|
||||
body: errorBody,
|
||||
isDismissible: isDismissible,
|
||||
buttons: const [
|
||||
buttons: [
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
labelText: context.l10n.ok,
|
||||
buttonAction: ButtonAction.first,
|
||||
isInAlert: true,
|
||||
),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.secondary,
|
||||
labelText: "OK",
|
||||
isInAlert: true,
|
||||
labelText: context.l10n.contactSupport,
|
||||
buttonAction: ButtonAction.second,
|
||||
onTap: () async {
|
||||
await sendLogs(
|
||||
context,
|
||||
context.l10n.contactSupport,
|
||||
"support@ente.io",
|
||||
postShare: () {},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
display_name: Auth
|
||||
license: GPLv3
|
||||
|
||||
metainfo: linux/packaging/ente_auth.appdata.xml
|
||||
|
||||
icon: assets/icons/auth-icon.png
|
||||
|
||||
keywords:
|
||||
|
||||
@@ -10,6 +10,8 @@ license: GPLv3
|
||||
icon: assets/icons/auth-icon.png
|
||||
installed_size: 36000
|
||||
|
||||
metainfo: linux/packaging/ente_auth.appdata.xml
|
||||
|
||||
dependencies:
|
||||
- libwebkit2gtk-4.0-37
|
||||
- libsqlite3-0
|
||||
|
||||
31
auth/linux/packaging/ente_auth.appdata.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>ente_auth</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>AGPL-3.0</project_license>
|
||||
<name>Ente Auth</name>
|
||||
<summary>Open source 2FA authenticator, with end-to-end encrypted backups</summary>
|
||||
<description>
|
||||
<p>Auth provides end-to-end encrypted cloud backups so you don't have to worry about losing your tokens. Our cryptography has been externally audited.</p>
|
||||
<p>Auth has an app for every platform. Mobile, desktop and web. Your codes sync across all your devices, end-to-end encrypted.</p>
|
||||
<p>Auth also comes with Offline mode, tags, icons, pins, import/export and more</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">ente_auth.desktop</launchable>
|
||||
<url type="homepage">https://ente.io/auth</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/ente-io/ente/main/.github/assets/auth.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="3.0.12" date="2024-06-17"/>
|
||||
</releases>
|
||||
<provides>
|
||||
<id>ente_auth.desktop</id>
|
||||
</provides>
|
||||
<content_rating type="oars-1.0" />
|
||||
<developer id="io.github.ente-io.ente">
|
||||
<name>Ente.io Developers</name>
|
||||
</developer>
|
||||
<update_contact>human@ente.io</update_contact>
|
||||
</component>
|
||||
58
auth/linux/packaging/pacman/make_config.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
display_name: Auth
|
||||
package_name: auth
|
||||
maintainer:
|
||||
name: Ente.io Developers
|
||||
email: human@ente.io
|
||||
licenses:
|
||||
- GPLv3
|
||||
icon: assets/icons/auth-icon.png
|
||||
installed_size: 36000
|
||||
|
||||
metainfo: linux/packaging/ente_auth.appdata.xml
|
||||
|
||||
dependencies:
|
||||
- c-ares
|
||||
- ffmpeg
|
||||
- gtk3
|
||||
- http-parser
|
||||
- libevent
|
||||
- libvpx
|
||||
- libxslt
|
||||
- libxss
|
||||
- minizip
|
||||
- nss
|
||||
- re2
|
||||
- snappy
|
||||
- libnotify
|
||||
- libappindicator-gtk3
|
||||
|
||||
keywords:
|
||||
- Authentication
|
||||
- 2FA
|
||||
|
||||
generic_name: Ente Authentication
|
||||
|
||||
categories:
|
||||
- Utility
|
||||
|
||||
supported_mime_type:
|
||||
- x-scheme-handler/enteauth
|
||||
|
||||
postinstall_scripts:
|
||||
- gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
|
||||
- update-desktop-database -q
|
||||
- if [ ! -e /usr/lib/libsodium.so.23 ]; then
|
||||
- " ln -s /usr/lib/libsodium.so /usr/lib/libsodium.so.23"
|
||||
- fi
|
||||
|
||||
postupgrade_scripts:
|
||||
- post_install
|
||||
|
||||
postremove_scripts:
|
||||
- gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
|
||||
- update-desktop-database -q
|
||||
- if [ -e /usr/lib/libsodium.so.23 ]; then
|
||||
- rm /usr/lib/libsodium.so.23
|
||||
- fi
|
||||
|
||||
startup_notify: false
|
||||
@@ -9,6 +9,8 @@ url: https://github.com/ente-io/ente
|
||||
|
||||
display_name: Auth
|
||||
|
||||
metainfo: linux/packaging/ente_auth.appdata.xml
|
||||
|
||||
requires:
|
||||
- libsqlite3x
|
||||
- webkit2gtk4.0
|
||||
|
||||
@@ -26,11 +26,11 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- ReachabilitySwift (5.2.2)
|
||||
- ReachabilitySwift (5.2.3)
|
||||
- screen_retriever (0.0.1):
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (8.25.0)
|
||||
- sentry_flutter (7.20.1):
|
||||
- sentry_flutter (7.20.2):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry/HybridSDK (= 8.25.0)
|
||||
@@ -44,18 +44,21 @@ PODS:
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (3.45.3+1)":
|
||||
- "sqlite3/common (= 3.45.3+1)"
|
||||
- "sqlite3/common (3.45.3+1)"
|
||||
- "sqlite3/fts5 (3.45.3+1)":
|
||||
- "sqlite3 (3.46.0+1)":
|
||||
- "sqlite3/common (= 3.46.0+1)"
|
||||
- "sqlite3/common (3.46.0+1)"
|
||||
- "sqlite3/dbstatvtab (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/perf-threadsafe (3.45.3+1)":
|
||||
- "sqlite3/fts5 (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.45.3+1)":
|
||||
- "sqlite3/perf-threadsafe (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- "sqlite3/rtree (3.46.0+1)":
|
||||
- sqlite3/common
|
||||
- sqlite3_flutter_libs (0.0.1):
|
||||
- FlutterMacOS
|
||||
- "sqlite3 (~> 3.45.3+1)"
|
||||
- "sqlite3 (~> 3.46.0+1)"
|
||||
- sqlite3/dbstatvtab
|
||||
- sqlite3/fts5
|
||||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
@@ -152,23 +155,23 @@ SPEC CHECKSUMS:
|
||||
flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
|
||||
flutter_local_authentication: 85674893931e1c9cfa7c9e4f5973cb8c56b018b0
|
||||
flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4
|
||||
flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea
|
||||
flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
|
||||
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
||||
ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979
|
||||
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||
Sentry: cd86fc55628f5b7c572cabe66cc8f95a9d2f165a
|
||||
sentry_flutter: 4cb24c1055c556d7b27262ab2e179d1e5a0b9b0c
|
||||
sentry_flutter: 0cf2507eb90ff7a6aa3304e900dd7f08edbbefdf
|
||||
share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7
|
||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sodium_libs: d39bd76697736cb11ce4a0be73b9b4bc64466d6f
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqlite3: 02d1f07eaaa01f80a1c16b4b31dfcbb3345ee01a
|
||||
sqlite3_flutter_libs: 8d204ef443cf0d5c1c8b058044eab53f3943a9c5
|
||||
sqlite3: 292c3e1bfe89f64e51ea7fc7dab9182a017c8630
|
||||
sqlite3_flutter_libs: 5ca46c1a04eddfbeeb5b16566164aa7ad1616e7b
|
||||
tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
|
||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
||||
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
|
||||
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
||||
|
||||
PODFILE CHECKSUM: f401c31c8f7c5571f6f565c78915d54338812dab
|
||||
|
||||
@@ -1443,10 +1443,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: "9f89a7e7dc36eac2035808427eba1c3fbd79e59c3a22093d8dace6d36b1fe89e"
|
||||
sha256: "62bbb4073edbcdf53f40c80775f33eea01d301b7b81417e5b3fb7395416258c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.23"
|
||||
version: "0.5.24"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 3.0.12+312
|
||||
version: 3.0.18+318
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -92,8 +92,8 @@ dependencies:
|
||||
url: https://github.com/tekartik/sqflite
|
||||
path: sqflite
|
||||
sqflite_common_ffi: ^2.3.0+4
|
||||
sqlite3: ^2.1.0
|
||||
sqlite3_flutter_libs: ^0.5.19+1
|
||||
sqlite3: ^2.4.3
|
||||
sqlite3_flutter_libs: ^0.5.24
|
||||
steam_totp: ^0.0.1
|
||||
step_progress_indicator: ^1.0.2
|
||||
styled_text: ^8.1.0
|
||||
@@ -132,6 +132,7 @@ flutter:
|
||||
- assets/custom-icons/icons/
|
||||
- assets/custom-icons/_data/
|
||||
- assets/svg/
|
||||
- assets/ca/
|
||||
|
||||
fonts:
|
||||
- family: Inter
|
||||
|
||||
@@ -58,6 +58,27 @@ var _disable2faCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var _disablePasskeyCmd = &cobra.Command{
|
||||
Use: "disable-passkey",
|
||||
Short: "Disable passkey for a user",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
recoverWithLog()
|
||||
var flags = &model.AdminActionForUser{}
|
||||
cmd.Flags().VisitAll(func(f *pflag.Flag) {
|
||||
if f.Name == "admin-user" {
|
||||
flags.AdminEmail = f.Value.String()
|
||||
}
|
||||
if f.Name == "user" {
|
||||
flags.UserEmail = f.Value.String()
|
||||
}
|
||||
})
|
||||
if flags.UserEmail == "" {
|
||||
return fmt.Errorf("user email is required")
|
||||
}
|
||||
return ctrl.DisablePasskeys(context.Background(), *flags)
|
||||
},
|
||||
}
|
||||
|
||||
var _deleteUser = &cobra.Command{
|
||||
Use: "delete-user",
|
||||
Short: "Delete a user",
|
||||
@@ -130,11 +151,13 @@ func init() {
|
||||
_listUsers.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_disable2faCmd.Flags().StringP("user", "u", "", "The email of the user to disable 2FA for. (required)")
|
||||
_disablePasskeyCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_disablePasskeyCmd.Flags().StringP("user", "u", "", "The email of the user to disable passkey for. (required)")
|
||||
_deleteUser.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
|
||||
_deleteUser.Flags().StringP("user", "u", "", "The email of the user to delete. (required)")
|
||||
_updateFreeUserStorage.Flags().StringP("admin-user", "a", "", "The email of the admin user.")
|
||||
_updateFreeUserStorage.Flags().StringP("user", "u", "", "The email of the user to update subscription for. (required)")
|
||||
// add a flag with no value --no-limit
|
||||
_updateFreeUserStorage.Flags().String("no-limit", "True", "When true, sets 100TB as storage limit, and expiry to current date + 100 years")
|
||||
_adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _updateFreeUserStorage, _listUsers, _deleteUser)
|
||||
_adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _disablePasskeyCmd, _updateFreeUserStorage, _listUsers, _deleteUser)
|
||||
}
|
||||
|
||||
2
cli/docs/generated/ente.md
generated
@@ -25,4 +25,4 @@ ente [flags]
|
||||
* [ente export](ente_export.md) - Starts the export process
|
||||
* [ente version](ente_version.md) - Prints the current version
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_account.md
generated
@@ -16,4 +16,4 @@ Manage account settings
|
||||
* [ente account list](ente_account_list.md) - list configured accounts
|
||||
* [ente account update](ente_account_update.md) - Update an existing account's export directory
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_account_add.md
generated
@@ -20,4 +20,4 @@ ente account add [flags]
|
||||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_account_get-token.md
generated
@@ -18,4 +18,4 @@ ente account get-token [flags]
|
||||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_account_list.md
generated
@@ -16,4 +16,4 @@ ente account list [flags]
|
||||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_account_update.md
generated
@@ -19,4 +19,4 @@ ente account update [flags]
|
||||
|
||||
* [ente account](ente_account.md) - Manage account settings
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
3
cli/docs/generated/ente_admin.md
generated
@@ -17,8 +17,9 @@ Commands for admin actions like disable or enabling 2fa, bumping up the storage
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
* [ente admin delete-user](ente_admin_delete-user.md) - Delete a user
|
||||
* [ente admin disable-2fa](ente_admin_disable-2fa.md) - Disable 2fa for a user
|
||||
* [ente admin disable-passkey](ente_admin_disable-passkey.md) - Disable passkey for a user
|
||||
* [ente admin get-user-id](ente_admin_get-user-id.md) - Get user id
|
||||
* [ente admin list-users](ente_admin_list-users.md) - List all users
|
||||
* [ente admin update-subscription](ente_admin_update-subscription.md) - Update subscription for user
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_admin_delete-user.md
generated
@@ -18,4 +18,4 @@ ente admin delete-user [flags]
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_admin_disable-2fa.md
generated
@@ -18,4 +18,4 @@ ente admin disable-2fa [flags]
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
21
cli/docs/generated/ente_admin_disable-passkey.md
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
## ente admin disable-passkey
|
||||
|
||||
Disable passkey for a user
|
||||
|
||||
```
|
||||
ente admin disable-passkey [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-a, --admin-user string The email of the admin user.
|
||||
-h, --help help for disable-passkey
|
||||
-u, --user string The email of the user to disable passkey for. (required)
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
2
cli/docs/generated/ente_admin_get-user-id.md
generated
@@ -18,4 +18,4 @@ ente admin get-user-id [flags]
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_admin_list-users.md
generated
@@ -17,4 +17,4 @@ ente admin list-users [flags]
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
@@ -23,4 +23,4 @@ ente admin update-subscription [flags]
|
||||
|
||||
* [ente admin](ente_admin.md) - Commands for admin actions
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_auth.md
generated
@@ -13,4 +13,4 @@ Authenticator commands
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
* [ente auth decrypt](ente_auth_decrypt.md) - Decrypt authenticator export
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_auth_decrypt.md
generated
@@ -16,4 +16,4 @@ ente auth decrypt [input] [output] [flags]
|
||||
|
||||
* [ente auth](ente_auth.md) - Authenticator commands
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_export.md
generated
@@ -16,4 +16,4 @@ ente export [flags]
|
||||
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
2
cli/docs/generated/ente_version.md
generated
@@ -16,4 +16,4 @@ ente version [flags]
|
||||
|
||||
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
|
||||
|
||||
###### Auto generated by spf13/cobra on 6-May-2024
|
||||
###### Auto generated by spf13/cobra on 22-Jun-2024
|
||||
|
||||
@@ -88,6 +88,29 @@ func (c *Client) Disable2Fa(ctx context.Context, userID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DisablePassKeyMFA(ctx context.Context, userID int64) error {
|
||||
var res interface{}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"userID": userID,
|
||||
}
|
||||
r, err := c.restClient.R().
|
||||
SetContext(ctx).
|
||||
SetResult(&res).
|
||||
SetBody(payload).
|
||||
Post("/admin/user/disable-passkeys")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.IsError() {
|
||||
return &ApiError{
|
||||
StatusCode: r.StatusCode(),
|
||||
Message: r.String(),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateFreePlanSub(ctx context.Context, userDetails *models.UserDetails, storageInBytes int64, expiryTimeInMicro int64) error {
|
||||
var res interface{}
|
||||
if userDetails.Subscription.ProductID != "free" {
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var AppVersion = "0.1.16"
|
||||
var AppVersion = "0.1.17"
|
||||
|
||||
func main() {
|
||||
cliDBPath, err := GetCLIConfigPath()
|
||||
|
||||
@@ -82,6 +82,27 @@ func (c *ClICtrl) Disable2FA(ctx context.Context, params model.AdminActionForUse
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClICtrl) DisablePasskeys(ctx context.Context, params model.AdminActionForUser) error {
|
||||
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userDetails, err := c.Client.GetUserIdFromEmail(accountCtx, params.UserEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.Client.DisablePassKeyMFA(accountCtx, userDetails.User.ID)
|
||||
if err != nil {
|
||||
if apiErr, ok := err.(*api.ApiError); ok && apiErr.StatusCode == 400 && strings.Contains(apiErr.Message, "Token is too old") {
|
||||
fmt.Printf("Error: Old admin token, please re-authenticate using `ente account add` \n")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
fmt.Println("Successfully disabled passkey for user")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClICtrl) UpdateFreeStorage(ctx context.Context, params model.AdminActionForUser, noLimit bool) error {
|
||||
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
|
||||
if err != nil {
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
)
|
||||
|
||||
func GetDB(path string) (*bolt.DB, error) {
|
||||
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
||||
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 5 * time.Second})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal(fmt.Sprintf("Failed to open db %s ", path), err)
|
||||
}
|
||||
return db, err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
## v1.7.2 (Unreleased)
|
||||
|
||||
- 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
|
||||
|
||||
@@ -128,3 +128,6 @@ watcher for the watch folders functionality.
|
||||
|
||||
[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.
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"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"
|
||||
|
||||
@@ -455,20 +455,51 @@ const allowExternalLinks = (webContents: WebContents) =>
|
||||
/**
|
||||
* Allow uploading to arbitrary S3 buckets.
|
||||
*
|
||||
* The files in the desktop app are served over the ente:// protocol. During
|
||||
* testing or self-hosting, we might be using a S3 bucket that does not allow
|
||||
* whitelisting a custom URI scheme. To avoid requiring the bucket to set an
|
||||
* "Access-Control-Allow-Origin: *" or do a echo-back of `Origin`, we add a
|
||||
* workaround here instead, intercepting the ACAO header and allowing `*`.
|
||||
* The files in the desktop app are served over the ente:// protocol. When that
|
||||
* is returned as the CORS allowed origin, "Access-Control-Allow-Origin:
|
||||
* ente://app", CORS requests fail.
|
||||
*
|
||||
* Further, during testing or self-hosting, file uploads involve a redirection
|
||||
* (This doesn't affect our production systems since we upload via a worker,
|
||||
* See: [Note: Passing credentials for self-hosted file fetches]).
|
||||
*
|
||||
* In some cases, we might be using a S3 bucket that does not allow whitelisting
|
||||
* a custom URI scheme. Echoing back the value of `Origin` (even if the bucket
|
||||
* would allow us to) would also not work, since the browser sends `null` as the
|
||||
* `Origin` for the redirected request (this is as per the CORS spec). So the
|
||||
* only way in such cases would be to require the bucket to set an
|
||||
* "Access-Control-Allow-Origin: *".
|
||||
*
|
||||
* To avoid these issues, we intercepting the ACAO header and set it to `*`.
|
||||
*
|
||||
* However, that cause problems with requests that use credentials since "*" is
|
||||
* not a valid value in such cases. One such example is the HCaptcha requests
|
||||
* made by Stripe when we initiate a payment within the desktop app:
|
||||
*
|
||||
* > Access to XMLHttpRequest at 'https://api2.hcaptcha.com/getcaptcha/xxx' from
|
||||
* > origin 'https://newassets.hcaptcha.com' has been blocked by CORS policy:
|
||||
* > The value of the 'Access-Control-Allow-Origin' header in the response must
|
||||
* > not be the wildcard '*' when the request's credentials mode is 'include'.
|
||||
* > The credentials mode of requests initiated by the XMLHttpRequest is
|
||||
* > controlled by the withCredentials attribute.
|
||||
*
|
||||
* So we only do this workaround if there was either no ACAO specified in the
|
||||
* response, or if the ACAO was "ente://app".
|
||||
*/
|
||||
const allowAllCORSOrigins = (webContents: WebContents) =>
|
||||
webContents.session.webRequest.onHeadersReceived(
|
||||
({ responseHeaders }, callback) => {
|
||||
const headers: NonNullable<typeof responseHeaders> = {};
|
||||
for (const [key, value] of Object.entries(responseHeaders ?? {}))
|
||||
if (key.toLowerCase() != "access-control-allow-origin")
|
||||
headers[key] = value;
|
||||
|
||||
headers["Access-Control-Allow-Origin"] = ["*"];
|
||||
for (const [key, value] of Object.entries(responseHeaders ?? {}))
|
||||
if (key.toLowerCase() == "access-control-allow-origin") {
|
||||
headers["Access-Control-Allow-Origin"] =
|
||||
value[0] == rendererURL ? ["*"] : value;
|
||||
} else {
|
||||
headers[key] = value;
|
||||
}
|
||||
|
||||
callback({ responseHeaders: headers });
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -152,4 +155,7 @@ export const markUploadedZipItems = (
|
||||
uploadStatusStore.set("zipItems", updated);
|
||||
};
|
||||
|
||||
export const clearPendingUploads = () => uploadStatusStore.clear();
|
||||
export const clearPendingUploads = () => {
|
||||
uploadStatusStore.clear();
|
||||
clearOpenZipCache();
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2259,7 +2259,7 @@ 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.0:
|
||||
lru-cache@^10.2, lru-cache@^10.2.0:
|
||||
version "10.2.2"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
|
||||
integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==
|
||||
|
||||
@@ -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 |
@@ -2,7 +2,7 @@
|
||||
|
||||
"Services" are Docker images we run on our instances and manage using systemd.
|
||||
|
||||
All our services (including museum itself) follow the same pattern:
|
||||
Generally our services (including museum itself) follow the same pattern:
|
||||
|
||||
- They're run on vanilla Ubuntu instances. The only expectation they have is
|
||||
for Docker to be installed.
|
||||
@@ -23,6 +23,8 @@ All our services (including museum itself) follow the same pattern:
|
||||
appropriate file from `/root/service-name` into the running Docker
|
||||
container.
|
||||
|
||||
- There are exceptions to this general pattern (See [sentry](sentry)).
|
||||
|
||||
## Systemd cheatsheet
|
||||
|
||||
```sh
|
||||
|
||||
@@ -48,10 +48,12 @@ When adding new services that sit behind Nginx,
|
||||
All the files we put into `/root/nginx/conf.d` get included in an `http` block.
|
||||
We can see this in the default configuration of nginx:
|
||||
|
||||
http {
|
||||
...
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
```
|
||||
http {
|
||||
...
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
```
|
||||
|
||||
> To view the default configuration, run the following command against the
|
||||
> [official Docker image for Nginx](https://hub.docker.com/_/nginx), which is
|
||||
|
||||
137
infra/services/sentry/README.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Sentry
|
||||
|
||||
- [Data flow](#understanding-the-data-flow)
|
||||
- [Setting up a new instance](#setting-up-a-new-instance)
|
||||
|
||||
## Data flow
|
||||
|
||||
### Overview
|
||||
|
||||
Clients tunnel events to sentry-reporter.ente.io, and include the DSN in the
|
||||
request. At the other end of the tunnel is a Cloudflare Worker which unwraps the
|
||||
event, remaps the DSN if needed, and sends it to our actual self-hosted Sentry
|
||||
instance, sentry.ente.io.
|
||||
|
||||
Among other things, this indirection allows us to treat the Sentry instance as
|
||||
disposable, and recreate it from scratch anytime. The existing DSN's change, but
|
||||
that is not a problem because we remap DSNs in the worker that handles the
|
||||
tunneled requests.
|
||||
|
||||
### DSN
|
||||
|
||||
Sentry identifies each project with a unique ID it calls **DSN** (Data Source
|
||||
Name). The DSN is a URL that includes the project ID. For example, here is the
|
||||
DSN for the debug builds of the photos mobile app:
|
||||
|
||||
https://ca5e686dd7f149d9bf94e620564cceba@sentry.ente.io/3
|
||||
|
||||
The DSN is considered public information and is included as part of the client's
|
||||
code. The DSN has 3 parts:
|
||||
|
||||
https://<public-key-for-project>@<host>/<project-id>
|
||||
|
||||
The `<host>` for our case is sentry.ente.io.
|
||||
|
||||
Each client has a separate project, and some clients have multiple projects
|
||||
(e.g. production / debug). Each of these get a separate DSN.
|
||||
|
||||
### Reporting crashes
|
||||
|
||||
Sentry supports
|
||||
[tunnels](https://docs.sentry.io/platforms/javascript/configuration/options/#tunnel).
|
||||
The idea is to encapsulate the entire "original" HTTP event which would've been
|
||||
reported to some Sentry instance, and instead send this encapsulated event to a
|
||||
URL that is hosted alongside the app itself (say, example.org/sentry). At the
|
||||
other end of the tunnel is a service that unwraps the original payload and
|
||||
forwards it to the actual Sentry instance.
|
||||
|
||||
Usage on the client is simple - the mobile SDKs for Sentry support a `tunnel`
|
||||
parameter which can be set to "https://sentry-reporter.ente.io"
|
||||
|
||||
The other end of the tunnel is handled by a Cloudflare Worker that listens for
|
||||
incoming requests to 'https://sentry-reporter.ente.io', and forwards the
|
||||
requests to `sentry.ente.io`. Before forwarding, it also remaps the DSNs sent by
|
||||
the client with the latest ones. This allows us to hardcode the DSN in the
|
||||
client - if the DSN on the Sentry backend changes, we can just update or add a
|
||||
new mapping in the worker.
|
||||
|
||||
The source code for this worker is in
|
||||
[workers/sentry-reporter](../../workers/sentry-reporter).
|
||||
|
||||
## Setting up a new instance
|
||||
|
||||
### Overview
|
||||
|
||||
The upstream documentation is at https://develop.sentry.dev/self-hosted/.
|
||||
|
||||
We follow their steps (clone their setup, modify the configuration, and run the
|
||||
`./install.sh` that they provide). This results in a Sentry installation being
|
||||
available at localhost:9000.
|
||||
|
||||
Then, we install an nginx service that terminates the Cloudflare TLS and reverse
|
||||
proxies to localhost:9000.
|
||||
|
||||
To update Sentry just fetch the latest upstream and re-run `./install.sh`.
|
||||
|
||||
### Steps
|
||||
|
||||
> The following assumes that you have already provisioned new instances using
|
||||
> our standard process.
|
||||
|
||||
- `cd /home/ente && git clone https://github.com/getsentry/self-hosted sentry`
|
||||
- Checkout the latest tag, e.g. `git checkout 24.2.0` (Sentry uses CalVer, so
|
||||
this'll be the latest `year.month.0`)
|
||||
- Run `sudo ./install.sh`
|
||||
|
||||
The rest of this section describes the remaining three steps:
|
||||
|
||||
- Modify configuration
|
||||
- Configure and start external nginx
|
||||
- Start the cluster
|
||||
|
||||
### Configuration
|
||||
|
||||
Modify `sentry/config.yml`, adding relevant bits from the contents of
|
||||
`config.yml` (from this repository) and the mail credentials.
|
||||
|
||||
Next, modify `.env`, setting
|
||||
|
||||
SENTRY_EVENT_RETENTION_DAYS=30
|
||||
SENTRY_MAIL_HOST=ente.io
|
||||
|
||||
### Configure external nginx
|
||||
|
||||
Add the nginx service (See [services/nginx](../services/nginx/README.md)) to the
|
||||
instance.
|
||||
|
||||
Add the Sentry nginx conf and certificates (since this instance will be running
|
||||
only sentry, we can use sentry specific certificates instead of our general
|
||||
wildcard ones).
|
||||
|
||||
sudo mv sentry.nginx.conf /root/nginx/conf.d
|
||||
sudo tee /root/nginx/cert.pem
|
||||
sudo tee /root/nginx/key.pem
|
||||
|
||||
### Start Sentry
|
||||
|
||||
Sentry should automatically start when the instance boots. If needed (and for
|
||||
the first time), it can be started manually by
|
||||
|
||||
cd /home/ente/sentry
|
||||
sudo docker compose up -d
|
||||
|
||||
The (external) nginx service will also start automatically on boot, but
|
||||
if neded it can be manually started by
|
||||
|
||||
sudo systemctl start nginx
|
||||
|
||||
In their docs Sentry sometimes refers to commands like `sentry createuser`. To
|
||||
run them, prefix the command with `docker compose exec web`. e.g.
|
||||
|
||||
cd /home/ente/sentry
|
||||
sudo docker compose exec web sentry createuser
|
||||
|
||||
If needed, Sentry can be stopped by using
|
||||
|
||||
cd /home/ente/sentry
|
||||
sudo docker compose stop
|
||||
13
infra/services/sentry/config.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
###############
|
||||
# Mail Server #
|
||||
###############
|
||||
|
||||
mail.host: "smtp.example.org"
|
||||
mail.port: 587
|
||||
mail.username: ""
|
||||
mail.password: ""
|
||||
mail.use-tls: true
|
||||
|
||||
# ...
|
||||
|
||||
system.url-prefix: "https://sentry.ente.io"
|
||||