Compare commits
384 Commits
improvedas
...
cli-v0.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5c28f1a8e | ||
|
|
dd3d9c8d51 | ||
|
|
58b9121e52 | ||
|
|
429d9fdbe5 | ||
|
|
dcbdeca64e | ||
|
|
32faa7f4f8 | ||
|
|
ecb0d47055 | ||
|
|
6645bd59b0 | ||
|
|
34f92f93e5 | ||
|
|
00a293df02 | ||
|
|
8ebdab291c | ||
|
|
148ee3f2c4 | ||
|
|
4428996541 | ||
|
|
fdd2bffc07 | ||
|
|
dbf737092b | ||
|
|
5506652179 | ||
|
|
d1c9033866 | ||
|
|
795767b2cb | ||
|
|
544a1df21b | ||
|
|
1dffe49069 | ||
|
|
64dedb7edd | ||
|
|
7566702569 | ||
|
|
d006f74cd4 | ||
|
|
27191d777a | ||
|
|
c68a16a9a9 | ||
|
|
ed1e6df967 | ||
|
|
93f9848d02 | ||
|
|
aa0325d72c | ||
|
|
4510c14af2 | ||
|
|
dc709e7649 | ||
|
|
b7fdf6c66b | ||
|
|
9f5115cc08 | ||
|
|
a9bace7781 | ||
|
|
014fbfe0eb | ||
|
|
38cdfcf0a4 | ||
|
|
3f9107c497 | ||
|
|
8870738330 | ||
|
|
38cae5c3d9 | ||
|
|
e133e6272a | ||
|
|
c486b8f2c1 | ||
|
|
f6cbbbead6 | ||
|
|
3ecef5e751 | ||
|
|
ef64ce065b | ||
|
|
99fdbd8d40 | ||
|
|
ac4a68d64e | ||
|
|
dae5b29ef1 | ||
|
|
4451b489e4 | ||
|
|
b19281ea2b | ||
|
|
8e923fe443 | ||
|
|
fe47186ace | ||
|
|
326704a605 | ||
|
|
d560ed9a33 | ||
|
|
0a8f51832a | ||
|
|
d2112b984d | ||
|
|
50aad0c5d1 | ||
|
|
e6e721f0ba | ||
|
|
80b34f1aef | ||
|
|
d5a8586152 | ||
|
|
bfcd84c940 | ||
|
|
a4bc5fa0df | ||
|
|
ed406e7eb0 | ||
|
|
b4dc49ef2f | ||
|
|
483e3be682 | ||
|
|
17f0d77a31 | ||
|
|
c6f644ef8a | ||
|
|
01b566698f | ||
|
|
469f884d8c | ||
|
|
9e4412cbee | ||
|
|
f4bab262ca | ||
|
|
73fd63616d | ||
|
|
9362a4b9d3 | ||
|
|
6c5ea59506 | ||
|
|
90845bdb02 | ||
|
|
f6729be5ab | ||
|
|
344c5cc399 | ||
|
|
6e1ea29c39 | ||
|
|
d76c6dd63c | ||
|
|
f69daa4608 | ||
|
|
290564c973 | ||
|
|
b781f33e4b | ||
|
|
b8bc01561d | ||
|
|
734cb798d3 | ||
|
|
ac8ebd0ed3 | ||
|
|
fc5eb296d2 | ||
|
|
c05d8a8e44 | ||
|
|
24845a4735 | ||
|
|
2b490fe131 | ||
|
|
07f0cc9342 | ||
|
|
49ddd287d0 | ||
|
|
bffcd11100 | ||
|
|
25d6ebdb19 | ||
|
|
64a539adb0 | ||
|
|
3646809f06 | ||
|
|
fb0e857514 | ||
|
|
a1059c543b | ||
|
|
8fe2b9cb27 | ||
|
|
5e080a90e3 | ||
|
|
08255b3f8a | ||
|
|
f032739461 | ||
|
|
841da80c97 | ||
|
|
60b1c32567 | ||
|
|
bd6ac2c4fc | ||
|
|
eaccba5f22 | ||
|
|
562313b218 | ||
|
|
0650d176ee | ||
|
|
6bbd944de4 | ||
|
|
8aaad79897 | ||
|
|
d499549734 | ||
|
|
db22c5bc97 | ||
|
|
34f49362fd | ||
|
|
af21ff640d | ||
|
|
69e69c2e0f | ||
|
|
a0445fb4f6 | ||
|
|
8161403d84 | ||
|
|
0713e34aec | ||
|
|
b504f554b3 | ||
|
|
3d6af698b6 | ||
|
|
ff3ddb3d8d | ||
|
|
16817eceac | ||
|
|
500e40035f | ||
|
|
366da2c328 | ||
|
|
203d46b2cf | ||
|
|
0e772fcfb7 | ||
|
|
bbd6745372 | ||
|
|
dd1e0a9b1d | ||
|
|
940231e38d | ||
|
|
4c8db02de5 | ||
|
|
8af5aadd1b | ||
|
|
205feab4c2 | ||
|
|
60ab2b4427 | ||
|
|
612329f584 | ||
|
|
a5f4a676a7 | ||
|
|
9608cfaa4e | ||
|
|
ddd4d3e16c | ||
|
|
df0d48af73 | ||
|
|
c82193cae6 | ||
|
|
2c0928bd02 | ||
|
|
8c8ffa9397 | ||
|
|
3689ecb6e7 | ||
|
|
ca080ad6b2 | ||
|
|
48d9ac63bb | ||
|
|
887066962f | ||
|
|
cb2615b083 | ||
|
|
de459e68eb | ||
|
|
9cc559870c | ||
|
|
395774c0e4 | ||
|
|
b3a7aebf95 | ||
|
|
b2e56fc01e | ||
|
|
0e0761bac7 | ||
|
|
79d7fe18ea | ||
|
|
228dd90bce | ||
|
|
93380d05b4 | ||
|
|
4123197c6d | ||
|
|
cc3f398a78 | ||
|
|
48155692ff | ||
|
|
dd0f7d3142 | ||
|
|
325c963b7a | ||
|
|
fbf29585eb | ||
|
|
8a2cc858ae | ||
|
|
b931825d3b | ||
|
|
2dc9b015a6 | ||
|
|
32c2456f03 | ||
|
|
084027df31 | ||
|
|
852878e3f4 | ||
|
|
f07e88b2dc | ||
|
|
d2e526769d | ||
|
|
867fdb7e2c | ||
|
|
a830b771f8 | ||
|
|
cc21f1a36d | ||
|
|
9ff8469a54 | ||
|
|
cfafcf8278 | ||
|
|
1829bcfdcf | ||
|
|
608fec9129 | ||
|
|
f5c9fa3d6c | ||
|
|
4a21ee0fa9 | ||
|
|
da853fdfde | ||
|
|
f2928c8ab8 | ||
|
|
d34bcffafd | ||
|
|
67028a072c | ||
|
|
2bbf33287b | ||
|
|
e60df5c54a | ||
|
|
b100392d7e | ||
|
|
b2154429f3 | ||
|
|
e9f10f77d9 | ||
|
|
1d3452a1f0 | ||
|
|
4e9ff3024c | ||
|
|
c193377640 | ||
|
|
6f4b20ad6f | ||
|
|
ee86de6b30 | ||
|
|
7930e95f4a | ||
|
|
2c3f82023c | ||
|
|
1f6c5d9782 | ||
|
|
b4640935a8 | ||
|
|
e64ef1a7d8 | ||
|
|
346e205001 | ||
|
|
8193379fad | ||
|
|
d3b589e622 | ||
|
|
ec68a11ec3 | ||
|
|
ca949ac077 | ||
|
|
54092c8fba | ||
|
|
4b3f5e4cca | ||
|
|
aebe483d80 | ||
|
|
ea5cd4a7d0 | ||
|
|
15a745266d | ||
|
|
fdde16e76c | ||
|
|
39adba94dd | ||
|
|
ef33065c5b | ||
|
|
dab15b2429 | ||
|
|
c0367729a7 | ||
|
|
fa3d3bceed | ||
|
|
26051985d5 | ||
|
|
fe2f30a92c | ||
|
|
af3f2280d6 | ||
|
|
d513019e1b | ||
|
|
c611d43204 | ||
|
|
cd76da836d | ||
|
|
9086d37a7c | ||
|
|
7234aef6c7 | ||
|
|
20a4e78998 | ||
|
|
280fa9a171 | ||
|
|
13e0cf1826 | ||
|
|
498e651d6d | ||
|
|
66d58d1538 | ||
|
|
27f95e433a | ||
|
|
9053717699 | ||
|
|
82b6187e26 | ||
|
|
b7bf4e7015 | ||
|
|
fbd572f23a | ||
|
|
92d017a701 | ||
|
|
422adf0a62 | ||
|
|
f85a1da9c2 | ||
|
|
afffcec3f2 | ||
|
|
77715e4d05 | ||
|
|
34eb9d7fba | ||
|
|
01c3308019 | ||
|
|
2f699365fb | ||
|
|
622c4e7258 | ||
|
|
68003e203b | ||
|
|
b273ac3cf0 | ||
|
|
3d46b015e1 | ||
|
|
523317eb71 | ||
|
|
4ce913cda6 | ||
|
|
7fdf52309a | ||
|
|
186981014e | ||
|
|
0bde1ab22d | ||
|
|
b2f9c6ff6b | ||
|
|
6aa810b500 | ||
|
|
cf4d407f39 | ||
|
|
ac05f085c1 | ||
|
|
7e48953b6a | ||
|
|
6f4bb6bf95 | ||
|
|
0666fc0ac2 | ||
|
|
6f304cb7a1 | ||
|
|
30c368d99f | ||
|
|
adaa81f50c | ||
|
|
c8a5ca41a2 | ||
|
|
dce84c4262 | ||
|
|
f529460eda | ||
|
|
ae170acb30 | ||
|
|
bfca0730b2 | ||
|
|
c95260a228 | ||
|
|
da43e27688 | ||
|
|
2e442c2152 | ||
|
|
d15d2437fb | ||
|
|
860ca9852b | ||
|
|
eb8ce32acb | ||
|
|
05327bb028 | ||
|
|
47a965f0a1 | ||
|
|
f7a500b811 | ||
|
|
0ce25916e6 | ||
|
|
504bae5dd8 | ||
|
|
8bb748ae22 | ||
|
|
e5bc7b218d | ||
|
|
29ea968408 | ||
|
|
07cd9be3f4 | ||
|
|
946605554c | ||
|
|
2b00418695 | ||
|
|
1a43c0feb2 | ||
|
|
309d3321b9 | ||
|
|
25f2fc46a9 | ||
|
|
48fc966457 | ||
|
|
d2fd7dea97 | ||
|
|
a2e93489f2 | ||
|
|
5150dc00e1 | ||
|
|
68ebd1ef69 | ||
|
|
1d1fa29239 | ||
|
|
04b3e0c7fb | ||
|
|
624a8bf6a9 | ||
|
|
2bebd2ead7 | ||
|
|
e7deb0fb94 | ||
|
|
d37cb971aa | ||
|
|
4470e039eb | ||
|
|
564222b3f0 | ||
|
|
2e1c5d7684 | ||
|
|
b5e3bf8d4b | ||
|
|
fbff908c90 | ||
|
|
3cb9b12f26 | ||
|
|
c4d5bc5aa7 | ||
|
|
237fc3cdb1 | ||
|
|
96386e8f9e | ||
|
|
8df19efc1a | ||
|
|
a0f7c6f302 | ||
|
|
fdef3dc439 | ||
|
|
3285ccdb3a | ||
|
|
a27da1de31 | ||
|
|
d6885d66c3 | ||
|
|
15b2b05487 | ||
|
|
03c4d42a03 | ||
|
|
621d58ec0e | ||
|
|
e51f9f1e08 | ||
|
|
3517050c23 | ||
|
|
4561c8f85c | ||
|
|
48d0e250c6 | ||
|
|
632224b94c | ||
|
|
8ecb88cbb4 | ||
|
|
330600543e | ||
|
|
4a9fe006d5 | ||
|
|
e50ae02dbb | ||
|
|
bc7075f81a | ||
|
|
f8d2fda602 | ||
|
|
896d7402b4 | ||
|
|
55a16d053a | ||
|
|
9a1254b745 | ||
|
|
afe5809cb2 | ||
|
|
d6c4d5f87f | ||
|
|
9de5f01727 | ||
|
|
4569ae01df | ||
|
|
896001100c | ||
|
|
332c8d9695 | ||
|
|
6df8a2204f | ||
|
|
4a16fa8701 | ||
|
|
92dc6cacfa | ||
|
|
b40419bcea | ||
|
|
f84b2b5ad3 | ||
|
|
2da32c3193 | ||
|
|
3011248017 | ||
|
|
54be100830 | ||
|
|
c37b6e0441 | ||
|
|
c113e09204 | ||
|
|
19f93087db | ||
|
|
3f736e82ae | ||
|
|
4f6e97eafd | ||
|
|
8c75a2324c | ||
|
|
91a4b1143f | ||
|
|
79b37f16f5 | ||
|
|
e45792ad09 | ||
|
|
00769bdd7a | ||
|
|
89f58236fc | ||
|
|
eca48a4cc3 | ||
|
|
fe324c3124 | ||
|
|
c0ac43b6c8 | ||
|
|
af60ae46c1 | ||
|
|
d47287095d | ||
|
|
b9d4f9ff10 | ||
|
|
fc826e8acb | ||
|
|
f6377b98cb | ||
|
|
b8c6a67faa | ||
|
|
e18c79c895 | ||
|
|
f9c6151482 | ||
|
|
fb28b4ca28 | ||
|
|
a10f278d44 | ||
|
|
9c1ae27a21 | ||
|
|
37fa4ba7b6 | ||
|
|
6bd307a2cd | ||
|
|
2b34cfc688 | ||
|
|
bb957685b3 | ||
|
|
445f8c4635 | ||
|
|
f2bb1430fe | ||
|
|
eddb774b19 | ||
|
|
fabd6351d9 | ||
|
|
637f3522a9 | ||
|
|
5dda37a192 | ||
|
|
6b3c9ee19c | ||
|
|
a3ebd4c062 | ||
|
|
3d3588e64e | ||
|
|
017cb7eb96 | ||
|
|
bf36f415db | ||
|
|
24ea4374cf | ||
|
|
33656c8206 | ||
|
|
5448ca116c | ||
|
|
bfa652df36 | ||
|
|
fae54faffc | ||
|
|
d4f781bf35 | ||
|
|
9c4e72aa0f |
2
.github/workflows/auth-lint.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
- ".github/workflows/auth-lint.yml"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.19.3"
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
2
.github/workflows/auth-release.yml
vendored
@@ -29,7 +29,7 @@ on:
|
||||
- "auth-v*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.19.3"
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
workflow_dispatch: # Allow manually running the action
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.22.1"
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
2
.github/workflows/mobile-lint.yml
vendored
@@ -10,7 +10,7 @@ on:
|
||||
|
||||
env:
|
||||
|
||||
FLUTTER_VERSION: "3.22.1"
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
2
.github/workflows/mobile-release.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
- "photos-v*"
|
||||
|
||||
env:
|
||||
FLUTTER_VERSION: "3.22.1"
|
||||
FLUTTER_VERSION: "3.22.2"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
2
.github/workflows/server-publish.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
registry: ghcr.io
|
||||
enableBuildKit: true
|
||||
multiPlatform: true
|
||||
platform: linux/amd64,linux/arm64,linux/arm/v7
|
||||
platform: linux/amd64,linux/arm64
|
||||
buildArgs: GIT_COMMIT=${{ inputs.commit }}
|
||||
tags: ${{ inputs.commit }}, latest
|
||||
username: ${{ github.actor }}
|
||||
|
||||
71
SECURITY.md
@@ -1,51 +1,54 @@
|
||||
# Security Policy
|
||||
|
||||
Ente believes that working with security researchers across the globe is crucial
|
||||
to keeping our users safe. If you believe you've found a security issue in our
|
||||
product or service, we encourage you to notify us, by email (security@ente.io)
|
||||
or by [filling this
|
||||
form](https://github.com/ente-io/ente/security/advisories/new) We welcome
|
||||
working with you to resolve the issue promptly. Thanks in advance!
|
||||
product or service, we encourage you to notify us by email at security@ente.io
|
||||
or by
|
||||
[filling out this form](https://github.com/ente-io/ente/security/advisories/new).
|
||||
We welcome working with you to resolve the issue promptly. Thanks in advance!
|
||||
|
||||
## Disclosure Policy
|
||||
|
||||
- Let us know as soon as possible upon discovery of a potential security issue,
|
||||
and we'll make every effort to quickly resolve the issue.
|
||||
- Provide us a reasonable amount of time to resolve the issue before any
|
||||
disclosure to the public or a third-party. We may publicly disclose the issue
|
||||
before resolving it, if appropriate.
|
||||
- Make a good faith effort to avoid privacy violations, destruction of data, and
|
||||
interruption or degradation of our service. Only interact with accounts you
|
||||
own or with explicit permission of the account holder.
|
||||
- If you would like to encrypt your report, please use the PGP key with long ID
|
||||
`E273695C0403F34F74171932DF6DDDE98EBD2394` (available in the public keyserver
|
||||
pool).
|
||||
- Let us know as soon as possible upon discovery of a potential security
|
||||
issue, and we'll make every effort to quickly resolve the issue.
|
||||
- Provide us with a reasonable amount of time to resolve the issue before any
|
||||
disclosure to the public or a third party. We may publicly disclose the
|
||||
issue before resolving it if appropriate.
|
||||
- Make a good faith effort to avoid privacy violations, destruction of data,
|
||||
and interruption or degradation of our service. Only interact with accounts
|
||||
you own or with the explicit permission of the account holder.
|
||||
- If you would like to encrypt your report, please use the PGP key with long
|
||||
ID `E273695C0403F34F74171932DF6DDDE98EBD2394` (available in the public
|
||||
keyserver pool).
|
||||
|
||||
## In-scope
|
||||
|
||||
- Security issues in any current release of Ente's services. Product downloads
|
||||
are available at https://ente.io. Source code is available at
|
||||
https://github.com/ente-io.
|
||||
- Security issues in any current release of Ente's services. Product downloads
|
||||
are available at [https://ente.io](https://ente.io). Source code is
|
||||
available at [https://github.com/ente-io](https://github.com/ente-io).
|
||||
|
||||
## Exclusions
|
||||
|
||||
The following bug classes are out-of scope:
|
||||
The following bug classes are out of scope:
|
||||
|
||||
- Bugs that are already reported on any of [Ente's issue
|
||||
trackers](https://github.com/ente-io), or that we already know of (Note that
|
||||
some of our issue tracking is private)
|
||||
- Issues in an upstream software dependency (ex: Flutter, Next.js etc) which are
|
||||
already reported to the upstream maintainer
|
||||
- Attacks requiring physical access to a user's device
|
||||
- Self-XSS
|
||||
- Issues related to software or protocols not under ente's control
|
||||
- Vulnerabilities in outdated versions of ente
|
||||
- Missing security best practices that do not directly lead to a vulnerability
|
||||
- Issues that do not have any impact on the general public
|
||||
- Bugs that are already reported on any of
|
||||
[Ente's issue trackers](https://github.com/ente-io) or that we already know
|
||||
of (note that some of our issue tracking is private).
|
||||
- Issues in an upstream software dependency (e.g., Flutter, Next.js, etc.)
|
||||
that are already reported to the upstream maintainer.
|
||||
- Attacks requiring physical access to a user's device.
|
||||
- Self-XSS.
|
||||
- Issues related to software or protocols not under Ente's control.
|
||||
- Vulnerabilities in outdated versions of Ente.
|
||||
- Missing security best practices that do not directly lead to a
|
||||
vulnerability.
|
||||
- Issues that do not have any impact on the general public.
|
||||
|
||||
While researching, we'd like to ask you to refrain from:
|
||||
|
||||
- Denial of service
|
||||
- Spamming
|
||||
- Social engineering (including phishing) of Ente staff or contractors
|
||||
- Any physical attempts against Ente property or data centers
|
||||
- Denial of service
|
||||
- Spamming
|
||||
- Social engineering (including phishing) of Ente staff or contractors
|
||||
- Any physical attempts against Ente property or data centers
|
||||
|
||||
Thank you for helping keep Ente and our users safe!
|
||||
|
||||
@@ -6,7 +6,7 @@ FEATURES
|
||||
|
||||
- Secure Backups
|
||||
Auth provides end-to-end encrypted cloud backups so that you don't have to worry
|
||||
about losing your tokens. We use the same protocols ente Photos uses to encrypt
|
||||
about losing your tokens. We use the same protocols Ente Photos uses to encrypt
|
||||
and preserve your data.
|
||||
|
||||
- Multi Device Synchronization
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
{
|
||||
"title": "BitMEX"
|
||||
},
|
||||
{
|
||||
"title": "BitSkins"
|
||||
},
|
||||
{
|
||||
"title": "Bitstamp"
|
||||
},
|
||||
{
|
||||
"title": "Bitvavo",
|
||||
"hex": "0051FF"
|
||||
@@ -50,6 +56,9 @@
|
||||
{
|
||||
"title": "CERN"
|
||||
},
|
||||
{
|
||||
"title": "ChangeNOW"
|
||||
},
|
||||
{
|
||||
"title": "Channel Island Hosting",
|
||||
"slug": "cih",
|
||||
@@ -58,6 +67,9 @@
|
||||
{
|
||||
"title": "Cloudflare"
|
||||
},
|
||||
{
|
||||
"title": "CoinDCX"
|
||||
},
|
||||
{
|
||||
"title": "ConfigCat"
|
||||
},
|
||||
@@ -83,6 +95,9 @@
|
||||
{
|
||||
"title": "Discourse"
|
||||
},
|
||||
{
|
||||
"title": "DMarket"
|
||||
},
|
||||
{
|
||||
"title": "Doppler"
|
||||
},
|
||||
@@ -154,6 +169,10 @@
|
||||
{
|
||||
"title": "INWX"
|
||||
},
|
||||
{
|
||||
"title": "Itch.io",
|
||||
"slug": "itch_io"
|
||||
},
|
||||
{
|
||||
"title": "IVPN",
|
||||
"slug": "IVPN"
|
||||
@@ -202,6 +221,10 @@
|
||||
"slug": "local_wp",
|
||||
"altNames": ["LocalWP", "Local WP", "Local Wordpress"]
|
||||
},
|
||||
{
|
||||
"title": "Marketplace.tf",
|
||||
"slug": "marketplacedottf"
|
||||
},
|
||||
{
|
||||
"title": "Mastodon",
|
||||
"altNames": ["mstdn", "fediscience", "mathstodon", "fosstodon"],
|
||||
@@ -216,6 +239,9 @@
|
||||
{
|
||||
"title": "Microsoft"
|
||||
},
|
||||
{
|
||||
"title": "Migros"
|
||||
},
|
||||
{
|
||||
"title": "Mintos"
|
||||
},
|
||||
@@ -231,6 +257,10 @@
|
||||
"title": "MyFRITZ!Net",
|
||||
"slug": "myfritz"
|
||||
},
|
||||
{
|
||||
"title": "Name.com",
|
||||
"slug": "name_com"
|
||||
},
|
||||
{
|
||||
"title": "NextDNS"
|
||||
},
|
||||
@@ -341,6 +371,9 @@
|
||||
"title": "Skiff",
|
||||
"hex": "EF5A3C"
|
||||
},
|
||||
{
|
||||
"title": "Skinport"
|
||||
},
|
||||
{
|
||||
"title": "Snapchat"
|
||||
},
|
||||
@@ -397,6 +430,10 @@
|
||||
"title": "Ubisoft",
|
||||
"hex": "4285f4"
|
||||
},
|
||||
{
|
||||
"title": "Ubuntu One",
|
||||
"slug": "ubuntu_one"
|
||||
},
|
||||
{
|
||||
"title": "Unity",
|
||||
"hex": "858585"
|
||||
@@ -423,9 +460,7 @@
|
||||
{
|
||||
"title": "WorkOS",
|
||||
"slug": "workos",
|
||||
"altNames": [
|
||||
"Work OS"
|
||||
]
|
||||
"altNames": ["Work OS"]
|
||||
},
|
||||
{
|
||||
"title": "X",
|
||||
|
||||
3
auth/assets/custom-icons/icons/bitskins.svg
Normal file
|
After Width: | Height: | Size: 19 KiB |
28
auth/assets/custom-icons/icons/bitstamp.svg
Executable file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="layer" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 652 652" style="enable-background:new 0 0 652 652;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#003B2F;}
|
||||
</style>
|
||||
<path class="st0" d="M108.8,331.4c0-11.4-6.6-20.5-17.3-24.2c8.1-3.7,13.7-11.4,13.7-21.3c0-15.5-13-26.3-31.5-26.3H21v13.2
|
||||
c8.3,0,15,6.7,15,15s-6.7,15-15,15v11.9c8.3,0,15,6.7,15,15s-6.7,15-15,15V359h55c18.9,0,32.6-11.2,32.6-27.5 M49.3,273.9H71
|
||||
c8.9,0,15.2,5.8,15.2,13.9s-6.3,13.7-15.2,13.7H49.3C49.3,301.5,49.3,273.9,49.3,273.9z M49.3,344.5v-30H73
|
||||
c9.8,0,16.4,6.1,16.4,14.9s-6.6,15.1-16.4,15.1C73,344.5,49.3,344.5,49.3,344.5z M130.2,254.4c6.6,0,11.4,4.7,11.4,11.4
|
||||
s-4.7,11.4-11.4,11.4c-6.6,0-11.2-4.7-11.2-11.4S123.7,254.4,130.2,254.4 M120.7,286.5h18.9v72.4h-18.9V286.5L120.7,286.5z
|
||||
M176.2,286.4h20.1v14.4h-20.1v34.6c0,5.5,4.4,10.1,9.9,10.2c2.9,0,6.1-0.4,9.6-1.3l2.5,14.2c-5.8,1.5-11.2,2.2-16.4,2.2
|
||||
c-14.5,0-24.6-9.5-24.6-23.4v-67.4c0-2.6,2.1-4.7,4.7-4.7h14.2V286.4L176.2,286.4z M234.6,284.7c8.4,0,17.4,1.7,26.6,5l-4.1,13.6
|
||||
c-7.3-2.8-14.5-4.6-21-4.6c-6.5,0-11.2,3.1-11.2,7.8c0,13.1,38.7,3.6,38.7,31.6c0,13.2-11.9,22.5-29,22.5c-8.9,0-18.6-2-28.8-5.8
|
||||
l4-13.5c8.4,3.4,16.4,5.2,23.4,5.2c7,0,11.9-3.4,11.9-8.4c0-13.7-38.6-4.1-38.6-31.6c0-12.7,11.5-21.9,28.3-21.9 M293.7,286.4h20.1
|
||||
v14.4h-20.1v34.6c0,5.5,4.4,10.1,9.9,10.2c2.9,0,6.1-0.4,9.6-1.3l2.5,14.2c-5.8,1.5-11.2,2.2-16.4,2.2c-14.5,0-24.6-9.5-24.6-23.4
|
||||
v-67.4c0-2.7,2.2-4.7,4.7-4.7h14.2V286.4z M413.8,286.4h15.1l2.4,9.9c5.8-7.5,14.2-11.6,23.8-11.6c10.5,0,19,5,23.2,13.3
|
||||
c6.6-8.6,15.7-13.3,26.2-13.3c15.8,0,27.1,11,27.1,26.4v47.7h-18.9v-44.8c0-8.1-5.8-13.9-14-13.9c-9.6,0-16.4,7.3-16.4,17.6v41.1
|
||||
h-18.9v-44.8c0-8.1-5.8-13.9-13.9-13.9c-9.8,0-16.5,7.3-16.5,17.6v41.1h-18.9v-72.4H413.8z M547.1,286.4h15.1l2.4,9.3
|
||||
c5.3-7.1,13.6-11.1,23.2-11.1c19.5,0,33.3,15.7,33.3,38c0,22.3-13.7,37.9-33.3,37.9c-8.9,0-16.5-3.6-21.8-10v32.2
|
||||
c0,2.6-2.1,4.7-4.7,4.7H547L547.1,286.4L547.1,286.4z M582.8,299.6c-10,0-17.2,7.5-17.2,18.2v9.8c0,10.5,7.1,18.2,17.2,18.2
|
||||
c11.1,0,18.9-9.6,18.9-23C601.8,309.4,593.9,299.7,582.8,299.6 M378.1,327.5c0,10.5-7.1,18.2-17.2,18.2c-11.1,0-18.9-9.6-18.9-23
|
||||
c0-13.4,7.8-23.1,18.9-23.1c10,0,17.2,7.5,17.2,18.2V327.5L378.1,327.5z M396.7,323.3L396.7,323.3v-36.9h-15.1l-2.4,9.3
|
||||
c-5.3-7.1-13.6-11.1-23.2-11.1c-19.5,0-33.3,15.7-33.3,38c0,22.3,13.7,37.9,33.3,37.9c1.1,0,2.2,0,3.3-0.2
|
||||
c8.2-0.8,15.1-4.7,19.9-10.9l2.4,9.3h15.1L396.7,323.3L396.7,323.3z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
15
auth/assets/custom-icons/icons/changenow.svg
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
4
auth/assets/custom-icons/icons/coindcx.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 500 500">
|
||||
<path fill="#182954" d="m75.705 269.386 12.606 10.812a40.902 40.902 0 0 1-8.642 8.853 53.365 53.365 0 0 1-13.599 7.73 45.769 45.769 0 0 1-16.998 3.094 49.02 49.02 0 0 1-25.212-6.466A45.84 45.84 0 0 1 6.72 275.84a50.83 50.83 0 0 1-6.212-25.287 52.621 52.621 0 0 1 3.525-19.394 49.28 49.28 0 0 1 10.2-16.022 46.603 46.603 0 0 1 15.44-10.812 49.626 49.626 0 0 1 19.969-3.938 45.9 45.9 0 0 1 23.51 5.48A49.016 49.016 0 0 1 88.308 219.5l-12.744 11.244A39.368 39.368 0 0 0 64.938 220.2a27.358 27.358 0 0 0-15.296-3.933 27.636 27.636 0 0 0-16.147 4.632 30.695 30.695 0 0 0-10.478 12.508 38.957 38.957 0 0 0-3.688 16.879 36.724 36.724 0 0 0 3.684 16.442 29.719 29.719 0 0 0 10.184 11.793 27.208 27.208 0 0 0 15.44 4.358c4.608.197 9.203-.62 13.456-2.391a27.765 27.765 0 0 0 8.214-5.622l5.381-5.481M93.275 264.047a35.477 35.477 0 0 1 4.535-17.71 34.84 34.84 0 0 1 12.748-12.929 39.497 39.497 0 0 1 18.838-4.778 39.497 39.497 0 0 1 18.838 4.778 34.846 34.846 0 0 1 12.749 12.928 36.889 36.889 0 0 1 4.532 17.709 36.891 36.891 0 0 1-4.532 17.708 36.519 36.519 0 0 1-13.365 13.153 36.875 36.875 0 0 1-18.181 4.837 36.88 36.88 0 0 1-18.203-4.756 36.513 36.513 0 0 1-13.424-13.092 35.479 35.479 0 0 1-4.535-17.707v-.141zm35.979 21.224a16.949 16.949 0 0 0 10.623-3.23c2.804-2.121 5-4.93 6.375-8.151a24.848 24.848 0 0 0 2.124-9.698 24.293 24.293 0 0 0-2.124-9.697 20.265 20.265 0 0 0-6.375-8.15 19.056 19.056 0 0 0-10.623-3.233 19.057 19.057 0 0 0-10.625 3.233 20.118 20.118 0 0 0-6.231 8.009 24.296 24.296 0 0 0-2.125 9.697 24.713 24.713 0 0 0 2.125 9.839 19.985 19.985 0 0 0 6.374 8.15 16.949 16.949 0 0 0 10.624 3.231M168.905 202.628h16.856v17.71h-16.856v-17.71zm0 28.11h16.856v66.758h-16.856v-66.758zM192.416 297.495V230.88h16.147l.42 7.589a35.937 35.937 0 0 1 7.505-5.905 23.656 23.656 0 0 1 12.749-3.094 24.38 24.38 0 0 1 10.396 1.612 24.22 24.22 0 0 1 8.726 5.836 29.047 29.047 0 0 1 6.66 20.097v40.477H238.02v-40.335a13.257 13.257 0 0 0-.76-5.278 13.337 13.337 0 0 0-2.78-4.561 12.19 12.19 0 0 0-4.164-2.694 12.27 12.27 0 0 0-4.902-.82 14.974 14.974 0 0 0-6.377 1.24 14.87 14.87 0 0 0-5.236 3.82 18.046 18.046 0 0 0-4.534 12.51v36.118l-16.851.004z"/>
|
||||
<path fill="#FA4A29" d="m463.25 246.618 29.754-44.007h-28.187l-15.44 24.596-15.883-24.596h-31.163l1.416 1.967-.993-.416a63.329 63.329 0 0 0-23.083-4.046 50.453 50.453 0 0 0-25.92 6.607 46.609 46.609 0 0 0-14.308 12.929 40.334 40.334 0 0 0-15.582-11.806 65.028 65.028 0 0 0-26.344-5.077h-36.686v94.727h36.544a64.026 64.026 0 0 0 26.344-5.202A41.612 41.612 0 0 0 339.3 280.63c3.87 5.299 8.846 9.709 14.59 12.928a51.44 51.44 0 0 0 25.777 6.325 55.023 55.023 0 0 0 24.646-5.34l-1.982 2.953h27.76l18.558-29.108 19.122 29.108h31.73l-36.252-50.878zm-147.452 21.624a25.772 25.772 0 0 1-8.902 5.504 25.916 25.916 0 0 1-10.376 1.523h-10.334v-50.573h10.338c3.62-.305 7.264.165 10.685 1.378a25.427 25.427 0 0 1 9.147 5.65 26.146 26.146 0 0 1 6.374 18.271 24.821 24.821 0 0 1-1.597 9.836 24.965 24.965 0 0 1-5.343 8.436l.008-.025zm101.549 6.911-12.04-11.228a38.572 38.572 0 0 1-10.197 9.149 27.09 27.09 0 0 1-13.6 2.952 25.509 25.509 0 0 1-13.314-3.372 22.838 22.838 0 0 1-8.8-9.415 29.459 29.459 0 0 1-3.118-13.63c-.091-4.623.929-9.2 2.975-13.353a23.258 23.258 0 0 1 8.642-9.415 25.653 25.653 0 0 1 13.738-3.513 24.798 24.798 0 0 1 12.748 3.23 32.061 32.061 0 0 1 9.639 8.733l12.606-12.508 18.415 26.28-17.694 26.09z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
1
auth/assets/custom-icons/icons/dmarket.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 2000 1948.02"><defs><style>.cls-1,.cls-2{opacity:0.25;isolation:isolate;}.cls-1{fill:url(#linear-gradient);}.cls-2{fill:url(#linear-gradient-2);}.cls-3{fill:url(#linear-gradient-3);}.cls-4{fill:url(#linear-gradient-4);}</style><linearGradient id="linear-gradient" x1="83.62" y1="947.07" x2="878.54" y2="947.07" gradientTransform="matrix(1, 0, 0, -1, 0, 1923)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#00ba96"/><stop offset="0.52" stop-color="#00d9af"/><stop offset="1" stop-color="#00d9af"/></linearGradient><linearGradient id="linear-gradient-2" x1="1144.49" y1="948.99" x2="2001.4" y2="948.99" gradientTransform="matrix(1, 0, 0, -1, 0, 1923)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#008d85"/><stop offset="1" stop-color="#00ffe0"/></linearGradient><linearGradient id="linear-gradient-3" x1="250.91" y1="949" x2="1904.03" y2="949" gradientTransform="matrix(1, 0, 0, -1, 0, 1923)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#008d94"/><stop offset="1" stop-color="#00ffe0"/></linearGradient><linearGradient id="linear-gradient-4" y1="947.06" x2="794.89" y2="947.06" gradientTransform="matrix(1, 0, 0, -1, 0, 1923)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#00ba96"/><stop offset="0.52" stop-color="#00d9af"/><stop offset="1" stop-color="#00faaf"/></linearGradient></defs><title>dmt</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M857,890.24,625.08,489,389.28,83.76a168.38,168.38,0,0,0-54.57-56.49h-1.95a148.49,148.49,0,0,0-56.52,58.44L100.85,389.6a138.94,138.94,0,0,0,0,140.26L311.32,894.13c15.59,25.32,21.44,54.54,21.44,83.76h0a178.34,178.34,0,0,1-21.44,83.76L102.8,1422a138.94,138.94,0,0,0,0,140.26l175.39,303.89c13.64,23.38,33.13,44.8,56.52,58.44h2c23.39-13.64,40.93-33.12,54.57-56.49l233.86-405.18L857,1057.76A171,171,0,0,0,857,890.24Z"/><path class="cls-2" d="M1975.62,878.55,1741.76,475.31,1502.06,60.39a171.53,171.53,0,0,0-42.87-48.7C1449.44,3.9,1439.69,0,1428,0c-122.78,0-206.58,3.9-268.94,3.9-9.74,0-15.59,11.69-13.64,21.43l60.41,339c0,3.9,0,7.79-1.95,11.69-23.39,42.86-21.44,95.45,3.9,138.31l214.37,374c15.59,27.27,23.39,56.49,23.39,85.71s-7.8,58.44-23.39,85.71l-216.32,374c-25.33,42.86-25.33,95.45-3.9,138.31,2,3.9,2,7.79,2,11.69l-60.41,337c-2,9.74,3.9,21.43,13.64,21.43,56.52,0-23.39,5.84,276.73,5.84,5.85,0,13.64-2,19.49-3.9,21.44-7.79,35.08-33.12,46.77-54.54l239.71-416.87,231.91-403.24c37-58.47,37-130.53,3.9-190.92"/><path class="cls-3" d="M1880.13,890.24,1414.36,83.76C1385.13,33.12,1330.56,0,1270.15,0H338.61c-31.18,0-60.41,9.74-87.7,25.32v1.95a168.38,168.38,0,0,1,54.57,56.49L539.34,489c21.44-9.74,46.77-15.58,70.16-15.58H995.36c60.41,0,115,31.17,144.21,83.76L1332.5,890.24c29.23,50.65,29.23,114.93,0,167.53l-192.93,333.11c-29.23,50.65-85.75,83.76-144.21,83.76H611.44a168.21,168.21,0,0,1-70.16-15.58L307.43,1864.24a168.38,168.38,0,0,1-54.57,56.49v2c25.33,15.58,56.52,25.32,87.7,25.32H1274c60.41,0,115-31.17,144.21-83.76L1884,1057.76c27.31-52.59,27.31-114.93-3.87-167.52"/><path class="cls-4" d="M771.25,890.24,539.34,489,305.48,83.76a168.38,168.38,0,0,0-54.57-56.49H249a148.49,148.49,0,0,0-56.52,58.44L19,387.65a138.94,138.94,0,0,0,0,140.26L229.47,892.18c15.59,25.32,21.44,54.54,21.44,83.76h0a178.34,178.34,0,0,1-21.44,83.76L19,1422a138.94,138.94,0,0,0,0,140.26l175.4,303.92c13.64,23.38,33.13,44.8,56.52,58.44h2c23.39-13.64,40.93-33.12,54.57-56.49L541.3,1463l231.9-401.29C802.43,1005.17,802.43,942.83,771.25,890.24Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
6
auth/assets/custom-icons/icons/itch_io.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="235.452" width="261.728"
|
||||
viewBox="0 0 245.371 220.736">
|
||||
<path
|
||||
d="M31.99 1.365C21.287 7.72.2 31.945 0 38.298v10.516C0 62.144 12.46 73.86 23.773 73.86c13.584 0 24.902-11.258 24.903-24.62 0 13.362 10.93 24.62 24.515 24.62 13.586 0 24.165-11.258 24.165-24.62 0 13.362 11.622 24.62 25.207 24.62h.246c13.586 0 25.208-11.258 25.208-24.62 0 13.362 10.58 24.62 24.164 24.62 13.585 0 24.515-11.258 24.515-24.62 0 13.362 11.32 24.62 24.903 24.62 11.313 0 23.773-11.714 23.773-25.046V38.298c-.2-6.354-21.287-30.58-31.988-36.933C180.118.197 157.056-.005 122.685 0c-34.37.003-81.228.54-90.697 1.365zm65.194 66.217a28.025 28.025 0 0 1-4.78 6.155c-5.128 5.014-12.157 8.122-19.906 8.122a28.482 28.482 0 0 1-19.948-8.126c-1.858-1.82-3.27-3.766-4.563-6.032l-.006.004c-1.292 2.27-3.092 4.215-4.954 6.037a28.5 28.5 0 0 1-19.948 8.12c-.934 0-1.906-.258-2.692-.528-1.092 11.372-1.553 22.24-1.716 30.164l-.002.045c-.02 4.024-.04 7.333-.06 11.93.21 23.86-2.363 77.334 10.52 90.473 19.964 4.655 56.7 6.775 93.555 6.788h.006c36.854-.013 73.59-2.133 93.554-6.788 12.883-13.14 10.31-66.614 10.52-90.474-.022-4.596-.04-7.905-.06-11.93l-.003-.045c-.162-7.926-.623-18.793-1.715-30.165-.786.27-1.757.528-2.692.528a28.5 28.5 0 0 1-19.948-8.12c-1.862-1.822-3.662-3.766-4.955-6.037l-.006-.004c-1.294 2.266-2.705 4.213-4.563 6.032a28.48 28.48 0 0 1-19.947 8.125c-7.748 0-14.778-3.11-19.906-8.123a28.025 28.025 0 0 1-4.78-6.155 27.99 27.99 0 0 1-4.736 6.155 28.49 28.49 0 0 1-19.95 8.124c-.27 0-.54-.012-.81-.02h-.007c-.27.008-.54.02-.813.02a28.49 28.49 0 0 1-19.95-8.123 27.992 27.992 0 0 1-4.736-6.155zm-20.486 26.49l-.002.01h.015c8.113.017 15.32 0 24.25 9.746 7.028-.737 14.372-1.105 21.722-1.094h.006c7.35-.01 14.694.357 21.723 1.094 8.93-9.747 16.137-9.73 24.25-9.746h.014l-.002-.01c3.833 0 19.166 0 29.85 30.007L210 165.244c8.504 30.624-2.723 31.373-16.727 31.4-20.768-.773-32.267-15.855-32.267-30.935-11.496 1.884-24.907 2.826-38.318 2.827h-.006c-13.412 0-26.823-.943-38.318-2.827 0 15.08-11.5 30.162-32.267 30.935-14.004-.027-25.23-.775-16.726-31.4L46.85 124.08C57.534 94.073 72.867 94.073 76.7 94.073zm45.985 23.582v.006c-.02.02-21.863 20.08-25.79 27.215l14.304-.573v12.474c0 .584 5.74.346 11.486.08h.006c5.744.266 11.485.504 11.485-.08v-12.474l14.304.573c-3.928-7.135-25.79-27.215-25.79-27.215v-.006l-.003.002z"
|
||||
color="#000" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
3
auth/assets/custom-icons/icons/marketplacedottf.svg
Normal file
|
After Width: | Height: | Size: 22 KiB |
19
auth/assets/custom-icons/icons/migros.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.0"
|
||||
width="602.36218"
|
||||
height="139.53543"
|
||||
id="svg3058">
|
||||
<defs
|
||||
id="defs3060" />
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
d="M 106.369,119.88512 L 106.369,62.018665 L 81.544594,119.88512 L 67.772114,119.88512 L 43.359087,62.018665 L 43.359087,119.88512 L 17.716529,119.88512 L 17.716529,19.650275 L 52.045504,19.650275 L 75.627274,76.245395 L 100.30782,19.650275 L 132.00731,19.650275 L 132.00731,119.88512 L 106.369,119.88512 z M 151.74424,119.88514 L 151.74424,19.650295 L 173.67129,19.650295 C 175.59247,19.650295 177.51259,21.571475 177.51259,23.661675 L 177.51259,119.88514 L 151.74424,119.88514 z M 248.65971,62.160065 L 281.25389,62.160065 C 283.82526,62.160065 285.27873,64.264785 285.27873,66.736595 L 285.27873,118.51459 C 276.11148,120.56404 261.78448,121.82085 251.13365,121.82085 C 213.76593,121.82085 194.05842,104.00581 194.05842,69.633955 C 194.05948,38.962025 213.76593,17.714585 246.61239,17.714585 C 261.08007,17.714585 273.76688,21.571475 281.93349,27.080965 L 271.83223,44.330845 C 264.76546,41.165965 255.25983,38.962025 248.53357,38.962025 C 229.64739,38.962025 220.81534,51.492935 220.81534,69.633955 C 220.81534,89.002025 231.04275,100.96814 249.90412,100.96814 C 253.35105,100.96814 257.64767,100.84093 261.08007,100.30377 L 261.08007,82.644625 L 248.65971,82.644625 L 248.65971,62.160065 z M 342.46983,38.962025 L 329.85459,38.962025 L 329.85459,64.094705 L 342.46983,64.094705 C 349.99971,64.094705 355.91916,60.082975 355.91916,50.546515 C 355.92022,40.883215 349.99865,38.962025 342.46983,38.962025 z M 361.45735,119.88514 L 349.56211,92.294115 C 347.1314,86.671595 345.43451,83.888325 340.27794,83.888325 L 329.85459,83.888325 L 329.85459,119.88514 L 304.66452,119.88514 L 304.66452,23.661675 C 304.66452,21.571475 306.95349,19.650295 308.59192,19.650295 L 344.15113,19.650295 C 363.47597,19.650295 380.04625,23.661675 380.04625,48.611165 C 380.04625,59.785695 373.86247,71.230215 362.26026,73.547185 C 368.0401,75.510535 373.86247,82.913205 377.01176,90.951915 L 388.47046,119.88514 L 361.45735,119.88514 z M 444.16061,38.962025 C 430.64148,38.962025 421.01998,48.611165 421.01998,69.633955 C 421.02105,90.951915 430.64042,100.57341 444.15991,100.57341 C 455.75892,100.57341 465.25215,90.951915 465.25215,69.633955 C 465.25321,48.611165 455.75892,38.962025 444.16061,38.962025 z M 444.16061,121.82085 C 411.34321,121.82085 393.97817,98.638055 393.97817,69.633955 C 393.97817,40.883215 411.34215,17.714585 444.15991,17.714585 C 474.90235,17.714585 492.29396,40.883215 492.29396,69.633955 C 492.29502,98.636985 474.90128,121.82085 444.16061,121.82085 z M 541.64053,121.82085 C 524.689,121.82085 508.94892,115.74656 501.92857,110.91455 L 513.3575,90.655685 C 519.73014,94.512575 532.13207,100.4455 543.56101,100.4455 C 550.03179,100.4455 558.21187,99.202855 558.21187,92.012065 C 558.21187,85.258875 549.07227,83.196315 537.08986,79.762855 C 522.62431,75.623205 505.78439,69.859315 505.78439,50.405135 C 505.7851,29.439745 524.41723,17.714585 548.66337,17.714585 C 564.66778,17.714585 577.07254,23.378915 583.4023,29.439745 L 569.48526,45.277265 C 562.60593,41.165965 555.57104,37.973445 547.68719,37.973445 C 538.19396,37.973445 532.82585,41.576285 532.82585,46.816835 C 532.82691,52.015925 539.70518,54.671985 548.37813,57.285175 C 563.71002,62.018685 584.64565,66.850335 584.64565,86.926005 C 584.64671,107.60829 568.11435,121.82085 541.64053,121.82085 z "
|
||||
style="fill:#f60;fill-opacity:1;fill-rule:evenodd"
|
||||
id="polygon3036" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
25
auth/assets/custom-icons/icons/name_com.svg
Normal file
@@ -0,0 +1,25 @@
|
||||
<svg enable-background="new 0 0 1510.1 240.3" viewBox="0 0 1510.1 240.3"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="m873.5 203.7c0 16.2-11.9 29.1-28.9 29.1-16.4 0-28.6-12.9-28.6-29.1s12.2-30 28.6-30c17 0 28.9 13.7 28.9 30z"
|
||||
fill="#6eda78" />
|
||||
<g fill="#282828">
|
||||
<path
|
||||
d="m9.7 229v-135.4l38.7-9.4-5.9 43.6h4.2c2.4-10.1 6.2-18.6 11.3-25.7 5.2-7 11.8-12.4 19.8-16 8.2-3.8 17.6-5.7 28.4-5.7 14 0 26.1 3.2 36.3 9.7 10.1 6.3 17.9 15.5 23.3 27.7 5.6 12 8.3 26.3 8.3 43.1v68.1h-38.5v-57.9c0-11.2-1.7-20.7-5.1-28.5-3.4-8-8.4-14-14.9-18-6.5-4.2-14.4-6.3-23.5-6.3-13.7 0-24.4 4.6-32.1 13.7s-11.5 22.1-11.5 39.1v57.9z" />
|
||||
<path clip-rule="evenodd"
|
||||
d="m252.4 232.7c-19.6 0-36.4-3.9-45.7-11.7-9.3-8-14-18.7-14-32.2 0-13.1 4.7-23.6 14-31.4 25.1-21.6 103.6-13.3 108.6-11.6 0-3.3-.2-8.9-3.5-14.4-7.9-13.8-24.3-19.7-39-19.7-12.3 0-25.3 6.1-32.9 15.4-3 3.7-5.5 9.1-5.5 9.1h-36.8c.6-7 4.6-18.4 10.7-27 6-8.7 15.4-16.1 27-21.2 11.8-5.3 20.7-7.6 38-7.6 18 0 31.8 3 43.9 9.1s21.1 14.6 26.9 25.7c5.9 11 8.8 24 8.8 38.8v23.3 52h-37.7l6-30.9h-4.1c-1.9 8.5-5.4 14.9-9.6 19.6-4.3 4.7-9.8 7.6-19.5 10.5-9.5 2.8-21.4 4.2-35.6 4.2zm-23.2-46.4c-2-32.9 77-23.3 86.1-22.2 0 4.8-.3 9.5-1.4 14-5.8 23.3-38.1 28.4-58 26.6-14.5-1.3-26-6.6-26.7-18.4z"
|
||||
fill-rule="evenodd" />
|
||||
<path
|
||||
d="m375.3 94.7v134.3h38.7v-71.9c0-12.2 2.8-21.7 8.3-28.5 5.6-6.8 13.1-10.3 22.5-10.3 6.4 0 11.8 1.5 16.4 4.6 4.7 3 8.3 7.5 10.8 13.4 2.6 5.7 3.9 12.6 3.9 20.8v71.9h38.5v-71.9c0-12.2 2.8-21.7 8.3-28.5 5.7-6.8 13.3-10.3 22.8-10.3 6.4 0 11.8 1.5 16.4 4.6 4.7 3 8.3 7.5 10.8 13.4 2.4 5.7 3.7 12.6 3.7 20.8v71.9h38.7v-82.1c0-14.1-2.2-26-6.6-35.9-4.2-10.1-10.3-17.7-18.1-22.8s-17.1-7.7-27.9-7.7c-13.1 0-23.8 3.5-32.1 10.6-8.2 6.8-14 17.1-17.4 30.8h-3.4c-1.1-7.8-3.8-14.7-7.8-20.8-4.1-6.3-9.6-11.2-16.4-14.8-6.7-3.8-14.7-5.7-24-5.7-12.7 0-23.1 3.4-31.1 10.3-8 6.7-13.7 16.5-17.1 29.7h-4.2l5.1-36.2z" />
|
||||
<path clip-rule="evenodd"
|
||||
d="m718.3 232.7c-18 0-33.4-3.3-46.3-10-12.7-6.8-22.4-16-28.9-27.4-6.5-11.6-9.8-24.5-9.8-38.8s3.3-27.1 9.8-38.5c6.5-11.6 16.2-20.7 29.1-27.4 12.9-6.8 28.4-10.3 46.5-10.3s33.6 3.4 46.3 10.3c12.9 6.7 22.6 15.8 29.2 27.4 6.5 11.6 9.8 24.6 9.8 39.1 0 4-.7 10.2-.7 10.2h-133.4c.9 4.3 2.4 8.3 4.5 12.1 3.8 6.5 9.3 11.6 16.7 15.4 7.5 3.6 16.8 5.4 27.9 5.4 12.6 0 22.2-1.7 28.9-5.1 5.2-2.7 9.5-5.9 13-9.5h39.1c-2.6 6.7-6.7 13.4-12.2 20-6.4 7.6-15.4 14.1-27.2 19.4-11.5 5.2-25.6 7.7-42.3 7.7zm-43.8-98.3c-1.4 2.4-2.9 6.1-3.4 8.8h47.6 47.6c-.6-2.7-2-6.4-3.4-8.8-3.8-6.7-9.3-11.8-16.7-15.4-7.3-3.8-16.5-5.7-27.4-5.7-11.1 0-20.3 1.9-27.7 5.7-7.3 3.6-12.9 8.7-16.6 15.4z"
|
||||
fill-rule="evenodd" />
|
||||
<path
|
||||
d="m896.2 195.4c6.5 11.4 16.1 20.5 28.7 27.4 12.7 6.7 28.1 10 46.1 10 16 0 30.1-2.8 42.4-8.3 12.2-5.5 22-13.2 29.2-23.1s11.4-21.1 12.7-33.6h-38.7c-1.5 8.4-6.1 15.4-14 21.1-7.8 5.7-18.4 8.6-31.6 8.6-9.8 0-18.1-1.8-25-5.4-6.9-3.8-12.1-8.7-15.7-14.8s-5.4-12.9-5.4-20.5c0-7.4 1.8-14.2 5.4-20.2 3.6-6.3 8.8-11.2 15.7-14.8s15.2-5.4 25-5.4c8.8 0 16.5 1.4 23 4.3 6.5 2.7 11.7 6.2 15.4 10.6 3.8 4.4 6.1 9.3 7.1 14.8h38.7c-1.3-12.7-5.6-24-12.7-33.6-7.2-9.9-16.9-17.6-29.2-23.1-12.2-5.7-26.4-8.6-42.4-8.6-18 0-33.3 3.4-46.1 10.3-12.6 6.7-22.1 15.8-28.7 27.4-6.5 11.6-9.8 24.4-9.8 38.5.1 13.9 3.4 26.8 9.9 38.4z" />
|
||||
<path clip-rule="evenodd"
|
||||
d="m1159.2 232.7c-18.6 0-34.5-3.3-47.5-10-13.1-6.8-22.9-16-29.6-27.4-6.5-11.6-9.8-24.5-9.8-38.8s3.3-27.1 9.8-38.5c6.7-11.6 16.6-20.7 29.6-27.4 13.1-6.8 28.9-10.3 47.5-10.3 18.5 0 34.2 3.4 47.3 10.3 13.1 6.7 22.9 15.8 29.4 27.4 6.7 11.4 10 24.2 10 38.5s-3.3 27.2-10 38.8c-6.5 11.4-16.3 20.5-29.4 27.4-13 6.7-28.8 10-47.3 10zm0-35.3c10.3 0 19-1.8 26.2-5.4 7.3-3.6 12.8-8.5 16.4-14.5 3.8-6.1 5.6-13 5.6-20.8 0-7.4-1.9-14.2-5.6-20.2-3.6-6.3-9.1-11.2-16.4-14.8-7.2-3.6-15.9-5.4-26.2-5.4-10.5 0-19.4 1.8-26.7 5.4-7.2 3.6-12.7 8.6-16.4 14.8-3.6 6.1-5.4 12.8-5.4 20.2 0 7.8 1.8 14.7 5.4 20.8 3.8 6.1 9.2 10.9 16.4 14.5 7.4 3.6 16.3 5.4 26.7 5.4z"
|
||||
fill-rule="evenodd" />
|
||||
<path
|
||||
d="m1265.3 93.6v135.4h38.7v-71.9c0-12.2 2.8-21.7 8.3-28.5 5.6-6.8 13.1-10.3 22.5-10.3 6.4 0 11.8 1.5 16.4 4.6 4.7 3 8.3 7.5 10.8 13.4 2.6 5.7 3.9 12.6 3.9 20.8v71.9h38.5v-71.9c0-12.2 2.8-21.7 8.3-28.5 5.7-6.8 13.3-10.3 22.8-10.3 6.4 0 11.8 1.5 16.4 4.6 4.7 3 8.3 7.5 10.8 13.4 2.4 5.7 3.7 12.6 3.7 20.8v71.9h38.7v-82.1c0-14.1-2.2-26-6.6-35.9-4.2-10.1-10.3-17.7-18.1-22.8s-17.1-7.7-27.9-7.7c-13.1 0-23.8 3.5-32.1 10.6-8.2 6.8-14 17.1-17.4 30.8h-3.4c-1.1-7.8-3.8-14.7-7.8-20.8-4.1-6.3-9.6-11.2-16.4-14.8-6.7-3.8-14.7-5.7-24-5.7-12.7 0-23.1 3.4-31.1 10.3-8 6.7-13.7 16.5-17.1 29.7h-4.2l5.1-36.2z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
3
auth/assets/custom-icons/icons/skinport.svg
Normal file
|
After Width: | Height: | Size: 34 KiB |
113
auth/assets/custom-icons/icons/ubuntu_one.svg
Normal file
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3039"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
width="240.20215"
|
||||
height="98.041267"
|
||||
sodipodi:docname="U1_logo.svg">
|
||||
<metadata
|
||||
id="metadata3045">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3043" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1022"
|
||||
inkscape:window-height="529"
|
||||
id="namedview3041"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="3.5580214"
|
||||
inkscape:cx="188.39168"
|
||||
inkscape:cy="46.745142"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3039" />
|
||||
<path
|
||||
style="fill:#dd4713;fill-opacity:1;stroke:none"
|
||||
d="m 0,13.135439 0.31287126,55.797305 c 0,0 -0.29397798,23.453759 25.17115774,28.396822 14.646306,2.843004 42.347094,-3.749492 42.347094,-3.749492 l -0.220563,-80.503585 -22.276334,0 0,62.638417 -20.95299,0 0,-41.464863 -9.04287,0 10.586775,-21.394113 z"
|
||||
id="path3049"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccsccccccccc" />
|
||||
<g
|
||||
id="g3898"
|
||||
transform="scale(2.2196062,2.2196062)">
|
||||
<path
|
||||
d="m 47.937238,17.527712 c -0.49137,0.12284 -1.143956,0.253358 -1.95776,0.391552 -0.798468,0.138195 -1.727443,0.207292 -2.786929,0.207293 -0.921305,-10e-7 -1.696731,-0.130518 -2.32628,-0.391552 -0.629558,-0.27639 -1.136272,-0.660264 -1.520143,-1.151624 -0.383877,-0.491358 -0.660267,-1.067169 -0.829169,-1.727435 -0.168907,-0.675616 -0.253359,-1.420332 -0.253358,-2.23415 l 0,-6.7254823 2.14202,0 0,6.2648323 c -3e-6,1.458728 0.230321,2.502865 0.690975,3.132417 0.460644,0.629556 1.23607,0.944333 2.326279,0.944331 0.230318,2e-6 0.46832,-0.0077 0.714007,-0.02303 0.245672,-0.01535 0.475996,-0.03071 0.690974,-0.04606 0.214961,-0.03071 0.406898,-0.05374 0.575812,-0.0691 0.184251,-0.03071 0.314768,-0.06142 0.391552,-0.09213 l 0,-10.1112553 2.14202,0 0,11.6313983"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#dd4713;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3871"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 53.207382,6.4260606 c 0.26103,-0.1688932 0.652582,-0.3454753 1.174656,-0.5297469 0.537419,-0.1842476 1.151617,-0.2763774 1.842598,-0.2763897 0.859871,1.23e-5 1.619942,0.153562 2.280214,0.4606495 0.67561,0.3071111 1.243743,0.7370502 1.704403,1.2898185 0.460638,0.5527892 0.806125,1.2130528 1.036462,1.9807926 0.245667,0.7677564 0.368507,1.6122804 0.368519,2.5335724 -1.2e-5,0.967368 -0.145884,1.842602 -0.437617,2.625701 -0.276401,0.767752 -0.67563,1.420338 -1.197688,1.957761 -0.52208,0.537425 -1.151634,0.952009 -1.888663,1.243753 -0.737047,0.291745 -1.566215,0.437617 -2.487507,0.437617 -0.998079,0 -1.88099,-0.0691 -2.648734,-0.207292 -0.767752,-0.138195 -1.397306,-0.27639 -1.888663,-0.414585 l 0,-17.15919172 2.14202,-0.36851956283681 0,6.42605988283681 m 0,9.5815084 c 0.214965,0.06142 0.514387,0.122842 0.898266,0.18426 0.399224,0.04607 0.890583,0.0691 1.474078,0.0691 1.151617,2e-6 2.072915,-0.376195 2.763897,-1.128591 0.690965,-0.767745 1.036451,-1.85027 1.036461,-3.247578 -10e-6,-0.614193 -0.06143,-1.190004 -0.184259,-1.727436 C 59.072975,9.619905 58.87336,9.159256 58.59698,8.7753728 58.320582,8.3761528 57.95974,8.0690534 57.514454,7.8540739 57.084507,7.6237594 56.562438,7.5085972 55.948246,7.5085868 c -0.583495,1.04e-5 -1.120919,0.099818 -1.612273,0.2994221 -0.491364,0.1996247 -0.867561,0.4069167 -1.128591,0.6218768 l 0,7.5776833"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#dd4713;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3873"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 73.905311,17.527712 c -0.49137,0.12284 -1.143957,0.253358 -1.95776,0.391552 -0.798468,0.138195 -1.727443,0.207292 -2.78693,0.207293 -0.921304,-10e-7 -1.69673,-0.130518 -2.326279,-0.391552 -0.629558,-0.27639 -1.136272,-0.660264 -1.520143,-1.151624 -0.383877,-0.491358 -0.660267,-1.067169 -0.829169,-1.727435 -0.168907,-0.675616 -0.253359,-1.420332 -0.253358,-2.23415 l 0,-6.7254823 2.14202,0 0,6.2648323 c -4e-6,1.458728 0.230321,2.502865 0.690974,3.132417 0.460645,0.629556 1.236071,0.944333 2.32628,0.944331 0.230318,2e-6 0.46832,-0.0077 0.714007,-0.02303 0.245672,-0.01535 0.475996,-0.03071 0.690974,-0.04606 0.214961,-0.03071 0.406898,-0.05374 0.575812,-0.0691 0.184251,-0.03071 0.314768,-0.06142 0.391552,-0.09213 l 0,-10.1112553 2.14202,0 0,11.6313983"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#dd4713;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3875"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 77.314487,6.2418008 c 0.491357,-0.1228281 1.143943,-0.2533453 1.95776,-0.391552 0.81381,-0.1381827 1.750463,-0.2072801 2.809962,-0.2072923 0.952001,1.22e-5 1.742782,0.1382069 2.372345,0.4145845 0.629544,0.2610463 1.128581,0.6372429 1.497111,1.1285912 0.383863,0.4760146 0.652575,1.0518259 0.806136,1.7274354 0.153538,0.6756275 0.230313,1.4203434 0.230325,2.2341494 l 0,6.725482 -2.14202,0 0,-6.264832 c -1e-5,-0.737032 -0.05375,-1.366586 -0.161227,-1.8886628 C 84.59274,9.1976435 84.431512,8.7753819 84.201197,8.4529182 83.970863,8.1304733 83.663764,7.9001488 83.279898,7.761944 82.896016,7.6084044 82.420012,7.5316296 81.851884,7.5316193 c -0.23033,1.03e-5 -0.468332,0.00769 -0.714006,0.023032 -0.245685,0.015365 -0.483687,0.038398 -0.714007,0.069097 -0.214974,0.015365 -0.414589,0.038398 -0.598844,0.069097 -0.168909,0.03072 -0.291749,0.053752 -0.36852,0.069097 l 0,10.1112547 -2.14202,0 0,-11.6313979"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#dd4713;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3877"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 91.700827,5.8963137 4.537397,0 0,1.7965329 -4.537397,0 0,5.5277934 c -3e-6,0.598848 0.04606,1.097885 0.138195,1.497111 0.09213,0.383877 0.230321,0.690976 0.414585,0.921299 0.184255,0.214971 0.414579,0.368521 0.690974,0.460649 0.276384,0.09213 0.598838,0.138197 0.967364,0.138195 0.644902,2e-6 1.159294,-0.0691 1.543175,-0.207292 0.399222,-0.153548 0.675611,-0.261033 0.829169,-0.322455 l 0.414585,1.7735 c -0.214978,0.107486 -0.591175,0.238003 -1.128591,0.391552 -0.537432,0.168905 -1.15163,0.253357 -1.842598,0.253358 -0.813819,-10e-7 -1.489438,-0.09981 -2.026858,-0.299422 -0.522072,-0.21497 -0.944334,-0.529747 -1.266786,-0.944332 -0.322456,-0.414583 -0.552781,-0.921297 -0.690974,-1.520143 -0.122841,-0.614196 -0.184261,-1.320525 -0.18426,-2.118988 l 0,-10.6870668 2.14202,-0.3685196 0,3.7082281"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#dd4713;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3879"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 108.21836,17.527712 c -0.49137,0.12284 -1.14395,0.253358 -1.95776,0.391552 -0.79847,0.138195 -1.72744,0.207292 -2.78693,0.207293 -0.9213,-10e-7 -1.69673,-0.130518 -2.32628,-0.391552 -0.62955,-0.27639 -1.13627,-0.660264 -1.52014,-1.151624 -0.383877,-0.491358 -0.660267,-1.067169 -0.829169,-1.727435 -0.168907,-0.675616 -0.253359,-1.420332 -0.253357,-2.23415 l 0,-6.7254823 2.142016,0 0,6.2648323 c 0,1.458728 0.23032,2.502865 0.69098,3.132417 0.46064,0.629556 1.23607,0.944333 2.32628,0.944331 0.23032,2e-6 0.46832,-0.0077 0.714,-0.02303 0.24568,-0.01535 0.476,-0.03071 0.69098,-0.04606 0.21496,-0.03071 0.4069,-0.05374 0.57581,-0.0691 0.18425,-0.03071 0.31477,-0.06142 0.39155,-0.09213 l 0,-10.1112553 2.14202,0 0,11.6313983"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#dd4713;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3881"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 48.692644,28.027864 c -1.2e-5,0.952013 -0.138207,1.811892 -0.414584,2.579636 -0.276402,0.767752 -0.667953,1.428016 -1.174656,1.980793 -0.49137,0.55278 -1.082536,0.982719 -1.773501,1.289819 -0.690982,0.291744 -1.443376,0.437616 -2.257182,0.437617 -0.81382,-10e-7 -1.566214,-0.145873 -2.257183,-0.437617 -0.690978,-0.3071 -1.289821,-0.737039 -1.796532,-1.289819 -0.491362,-0.552777 -0.875236,-1.213041 -1.151624,-1.980793 -0.276391,-0.767744 -0.414586,-1.627623 -0.414585,-2.579636 -10e-7,-0.936647 0.138194,-1.788848 0.414585,-2.556605 0.276388,-0.783095 0.660262,-1.451036 1.151624,-2.003825 0.506711,-0.552768 1.105554,-0.97503 1.796532,-1.266786 0.690969,-0.307088 1.443363,-0.460637 2.257183,-0.46065 0.813806,1.3e-5 1.5662,0.153562 2.257182,0.46065 0.690965,0.291756 1.282131,0.714018 1.773501,1.266786 0.506703,0.552789 0.898254,1.22073 1.174656,2.003825 0.276377,0.767757 0.414572,1.619958 0.414584,2.556605 m -2.23415,0 c -1e-5,-1.351232 -0.307109,-2.418402 -0.921299,-3.201514 -0.598853,-0.798449 -1.420343,-1.197678 -2.464474,-1.197689 -1.044145,1.1e-5 -1.873313,0.39924 -2.487507,1.197689 -0.598848,0.783112 -0.89827,1.850282 -0.898267,3.201514 -3e-6,1.351243 0.299419,2.42609 0.898267,3.224546 0.614194,0.783106 1.443362,1.174657 2.487507,1.174656 1.044131,10e-7 1.865621,-0.39155 2.464474,-1.174656 0.61419,-0.798456 0.921289,-1.873303 0.921299,-3.224546"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3883"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 51.144189,22.384908 c 0.491357,-0.122828 1.143943,-0.253346 1.95776,-0.391552 0.813809,-0.138183 1.750462,-0.20728 2.809962,-0.207293 0.952001,1.3e-5 1.742782,0.138207 2.372344,0.414585 0.629545,0.261046 1.128581,0.637243 1.497111,1.128591 0.383864,0.476015 0.652576,1.051826 0.806136,1.727436 0.153539,0.675627 0.230314,1.420343 0.230325,2.234149 l 0,6.725482 -2.14202,0 0,-6.264832 c -9e-6,-0.737032 -0.05375,-1.366586 -0.161227,-1.888663 -0.09214,-0.522061 -0.253366,-0.944322 -0.483682,-1.266786 -0.230333,-0.322445 -0.537433,-0.552769 -0.921299,-0.690974 -0.383882,-0.15354 -0.859886,-0.230314 -1.428013,-0.230325 -0.230331,1.1e-5 -0.468333,0.0077 -0.714007,0.02303 -0.245685,0.01536 -0.483687,0.0384 -0.714006,0.0691 -0.214975,0.01536 -0.41459,0.0384 -0.598845,0.0691 -0.168909,0.03072 -0.291748,0.05375 -0.368519,0.0691 l 0,10.111255 -2.14202,0 0,-11.631398"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3885"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 63.139815,28.050896 c -2e-6,-1.059487 0.153548,-1.980785 0.460649,-2.763897 0.307098,-0.798449 0.714004,-1.458713 1.220721,-1.980792 0.506711,-0.522059 1.0902,-0.91361 1.750468,-1.174656 0.660259,-0.261023 1.335877,-0.39154 2.026858,-0.391553 1.612264,1.3e-5 2.848339,0.506727 3.708228,1.520144 0.859867,0.998083 1.289806,2.525902 1.289818,4.583462 -1.2e-5,0.09214 -1.2e-5,0.214975 0,0.368519 -1.2e-5,0.138201 -0.0077,0.268718 -0.02303,0.391552 l -8.199561,0 c 0.09213,1.243758 0.452969,2.188088 1.082527,2.832994 0.629549,0.644912 1.612267,0.967366 2.948156,0.967364 0.752386,2e-6 1.38194,-0.06142 1.888663,-0.184259 0.522059,-0.138193 0.913611,-0.268711 1.174656,-0.391552 l 0.299422,1.796532 c -0.261045,0.138195 -0.721694,0.284068 -1.381948,0.437617 -0.644918,0.15355 -1.381957,0.230325 -2.211118,0.230325 -1.044145,0 -1.950088,-0.15355 -2.717831,-0.460649 -0.752398,-0.322454 -1.374274,-0.760071 -1.865631,-1.312851 -0.491361,-0.552778 -0.85988,-1.205364 -1.105558,-1.95776 -0.230326,-0.767745 -0.345489,-1.604591 -0.345487,-2.51054 m 8.222592,-1.174656 c 0.01535,-0.967356 -0.230334,-1.758137 -0.737039,-2.372345 -0.491367,-0.629544 -1.174663,-0.944321 -2.04989,-0.944331 -0.491365,10e-6 -0.928982,0.09982 -1.312851,0.299422 -0.368524,0.18427 -0.683301,0.429949 -0.944331,0.737039 -0.261039,0.307109 -0.468331,0.660273 -0.621877,1.059494 -0.138198,0.399237 -0.230328,0.806144 -0.27639,1.220721 l 5.942378,0"
|
||||
style="font-size:23.03247261px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
|
||||
id="path3887"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -6,7 +6,7 @@ FEATURES
|
||||
|
||||
- Secure Backups
|
||||
ente provides end-to-end encrypted cloud backups so that you don't have to worry
|
||||
about losing your tokens. We use the same protocols ente Photos uses to encrypt
|
||||
about losing your tokens. We use the same protocols Ente Photos uses to encrypt
|
||||
and preserve your data.
|
||||
|
||||
- Multi Device Synchronization
|
||||
|
||||
@@ -42,3 +42,7 @@ class InvalidStateError extends AssertionError {
|
||||
class SrpSetupNotCompleteError extends Error {}
|
||||
|
||||
class AuthenticatorKeyNotFound extends Error {}
|
||||
|
||||
class PassKeySessionNotVerifiedError extends Error {}
|
||||
|
||||
class PassKeySessionExpiredError extends Error {}
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
"privacy": "Privacy",
|
||||
"terms": "Terms",
|
||||
"checkForUpdates": "Check for updates",
|
||||
"checkStatus": "Check status",
|
||||
"downloadUpdate": "Download",
|
||||
"criticalUpdateAvailable": "Critical update available",
|
||||
"updateAvailable": "Update available",
|
||||
@@ -417,6 +418,9 @@
|
||||
"waitingForBrowserRequest": "Waiting for browser request...",
|
||||
"waitingForVerification": "Waiting for verification...",
|
||||
"passkey": "Passkey",
|
||||
"passKeyPendingVerification": "Verification is still pending",
|
||||
"loginSessionExpired" : "Session expired",
|
||||
"loginSessionExpiredDetails": "Your session has expired. Please login again.",
|
||||
"developerSettingsWarning":"Are you sure that you want to modify Developer settings?",
|
||||
"developerSettings": "Developer settings",
|
||||
"serverEndpoint": "Server endpoint",
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"codeIssuerHint": "Emittente",
|
||||
"codeSecretKeyHint": "Codice segreto",
|
||||
"codeAccountHint": "Account (username@dominio.it)",
|
||||
"codeTagHint": "Tag",
|
||||
"accountKeyType": "Tipo di chiave",
|
||||
"sessionExpired": "Sessione scaduta",
|
||||
"@sessionExpired": {
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
@@ -77,16 +79,19 @@
|
||||
"data": "Dati",
|
||||
"importCodes": "Importa codici",
|
||||
"importTypePlainText": "Testo in chiaro",
|
||||
"importTypeEnteEncrypted": "Esportazione Ente criptata",
|
||||
"passwordForDecryptingExport": "Password per decriptare il file esportato",
|
||||
"passwordEmptyError": "La password è obbligatoria",
|
||||
"importFromApp": "Importa codici da {appName}",
|
||||
"importGoogleAuthGuide": "Esporta i tuoi account da Google Authenticator in un codice QR utilizzando l'opzione \"Trasferisci Account\". Quindi, usando un altro dispositivo, scansiona il codice QR.\n\nSuggerimento: Puoi usare la webcam del tuo computer portatile per scattare una foto del codice QR.",
|
||||
"importSelectJsonFile": "Seleziona file JSON",
|
||||
"importSelectAppExport": "Seleziona il file di esportazione {appName}",
|
||||
"importEnteEncGuide": "Seleziona il file JSON criptato esportato da Ente",
|
||||
"importRaivoGuide": "Utilizza l'opzione \"Esporta i codici OTP in archivio Zip\" nelle impostazioni di Raivo.\n\nEstrai il file zip e importa il file JSON.",
|
||||
"importBitwardenGuide": "Utilizzare l'opzione \"Esporta vault\" all'interno di Bitwarden Tools e importa il file JSON non crittografato.",
|
||||
"importAegisGuide": "Usa l'opzione \"Esporta la cassaforte\" nelle impostazioni di Aegis.\n\nSe la tua cassaforte è criptata, dovrai inserire la password della cassaforte per decriptarla.",
|
||||
"import2FasGuide": "Utilizza l'opzione \"Impostazioni->Backup -Export\" in 2FAS.\n\nSe il backup è crittografato, è necessario inserire la password per decriptare il backup",
|
||||
"importLastpassGuide": "Usa l'opzione \"Trasferisci account\" all'interno delle impostazioni di Lastpass Authenticator e premi \"Esporta account su file\". Importa il JSON scaricato.",
|
||||
"exportCodes": "Esporta codici",
|
||||
"importLabel": "Importa",
|
||||
"importInstruction": "Per favore seleziona un file contenente una lista dei tuoi codici nel seguente formato",
|
||||
@@ -111,18 +116,22 @@
|
||||
"copied": "Copiato",
|
||||
"pleaseTryAgain": "Per favore riprova",
|
||||
"existingUser": "Accedi",
|
||||
"newUser": "Nuovo utente",
|
||||
"delete": "Cancella",
|
||||
"enterYourPasswordHint": "Inserisci la tua password",
|
||||
"forgotPassword": "Password dimenticata",
|
||||
"oops": "Oops",
|
||||
"suggestFeatures": "Suggerisci funzionalità",
|
||||
"faq": "FAQ",
|
||||
"faq_q_1": "Quanto è sicuro Auth?",
|
||||
"faq_a_1": "Tutti i codici di cui fai il backup tramite Auth sono memorizzati con crittografia end-to-end. Ciò significa che solo tu puoi accedere ai tuoi codici. Le nostre app sono open source e la nostra crittografia è stata verificata esternamente.",
|
||||
"faq_q_2": "Posso accedere ai miei codici sul desktop?",
|
||||
"faq_a_2": "Puoi accedere ai tuoi codici sul web @ auth.ente.io.",
|
||||
"faq_q_3": "Come posso cancellare i codici?",
|
||||
"faq_a_3": "Puoi eliminare un codice scorrendo il dito a sinistra sul codice in questione.",
|
||||
"faq_q_4": "Come posso supportare questo progetto?",
|
||||
"faq_a_4": "Puoi supportare lo sviluppo di questo progetto abbonandoti alla nostra app Photos @ ente.io.",
|
||||
"faq_q_5": "Come posso abilitare il blocco FaceID in Auth",
|
||||
"faq_a_5": "Puoi abilitare il blocco FaceID in Impostazioni → Sicurezza → Schermata di blocco.",
|
||||
"somethingWentWrongMessage": "Qualcosa è andato storto, per favore riprova",
|
||||
"leaveFamily": "Abbandona il piano famiglia",
|
||||
@@ -136,6 +145,8 @@
|
||||
"enterCodeHint": "Inserisci il codice di 6 cifre dalla tua app di autenticazione",
|
||||
"lostDeviceTitle": "Dispositivo perso?",
|
||||
"twoFactorAuthTitle": "Autenticazione a due fattori",
|
||||
"passkeyAuthTitle": "Verifica della passkey",
|
||||
"verifyPasskey": "Verifica passkey",
|
||||
"recoverAccount": "Recupera account",
|
||||
"enterRecoveryKeyHint": "Inserisci la tua chiave di recupero",
|
||||
"recover": "Recupera",
|
||||
@@ -147,6 +158,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"invalidQRCode": "Codice QR non valido",
|
||||
"noRecoveryKeyTitle": "Nessuna chiave di recupero?",
|
||||
"enterEmailHint": "Inserisci il tuo indirizzo email",
|
||||
"invalidEmailTitle": "Indirizzo email non valido",
|
||||
@@ -190,6 +202,9 @@
|
||||
"doThisLater": "Fallo più tardi",
|
||||
"saveKey": "Salva chiave",
|
||||
"save": "Salva",
|
||||
"send": "Invia",
|
||||
"saveOrSendDescription": "Vuoi salvarlo nel tuo spazio di archiviazione (cartella Download per impostazione predefinita) o inviarlo ad altre applicazioni?",
|
||||
"saveOnlyDescription": "Vuoi salvarlo nel tuo spazio di archiviazione (cartella Download per impostazione predefinita)?",
|
||||
"back": "Indietro",
|
||||
"createAccount": "Crea account",
|
||||
"passwordStrength": "Forza password: {passwordStrengthValue}",
|
||||
@@ -337,6 +352,7 @@
|
||||
"deleteCodeAuthMessage": "Autenticarsi per cancellare il codice",
|
||||
"showQRAuthMessage": "Autenticarsi per mostrare il codice QR",
|
||||
"confirmAccountDeleteTitle": "Conferma l'eliminazione dell'account",
|
||||
"confirmAccountDeleteMessage": "Questo account è collegato ad altre app di Ente, se ne utilizzi.\n\nI tuoi dati caricati, su tutte le app di Ente, saranno pianificati per la cancellazione e il tuo account verrà eliminato definitivamente.",
|
||||
"androidBiometricHint": "Verifica l'identità",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
@@ -397,5 +413,28 @@
|
||||
"doNotSignOut": "Non uscire",
|
||||
"hearUsWhereTitle": "Dove hai sentito parlare di Ente? (opzionale)",
|
||||
"hearUsExplanation": "Non teniamo traccia delle installazioni dell'app. Sarebbe utile se ci dicessi dove ci hai trovato!",
|
||||
"passkey": "Passkey"
|
||||
"recoveryKeySaved": "Chiave di recupero salvata nella cartella Download!",
|
||||
"waitingForBrowserRequest": "In attesa della richiesta del browser...",
|
||||
"waitingForVerification": "In attesa di verifica...",
|
||||
"passkey": "Passkey",
|
||||
"developerSettingsWarning": "Siete sicuri di voler modificare le impostazioni sviluppatore?",
|
||||
"developerSettings": "Impostazioni sviluppatore",
|
||||
"serverEndpoint": "Endpoint del server",
|
||||
"invalidEndpoint": "Endpoint invalido",
|
||||
"invalidEndpointMessage": "Spiacenti, l'endpoint inserito non è valido. Inserisci un endpoint valido e riprova.",
|
||||
"endpointUpdatedMessage": "Endpoint aggiornato con successo",
|
||||
"customEndpoint": "Connesso a {endpoint}",
|
||||
"pinText": "Fissa",
|
||||
"unpinText": "Sgancia",
|
||||
"pinnedCodeMessage": "{code} è stato fissato",
|
||||
"unpinnedCodeMessage": "{code} è stato sganciato",
|
||||
"tags": "Tag",
|
||||
"createNewTag": "Crea un nuovo tag",
|
||||
"tag": "Tag",
|
||||
"create": "Crea",
|
||||
"editTag": "Modifica tag",
|
||||
"deleteTagTitle": "Eliminare il tag?",
|
||||
"deleteTagMessage": "Sei sicuro di voler eliminare questo tag? Questa azione è irreversibile.",
|
||||
"somethingWentWrongParsingCode": "Non siamo riusciti ad analizzare i codici {x}.",
|
||||
"updateNotAvailable": "Aggiornamento non disponibile"
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
"pleaseVerifyDetails": "Por favor, verifique os detalhes e tente novamente",
|
||||
"codeIssuerHint": "Emissor",
|
||||
"codeSecretKeyHint": "Chave secreta",
|
||||
"codeAccountHint": "Conta (voce@dominio.com)",
|
||||
"codeAccountHint": "Conta (você@domínio.com)",
|
||||
"codeTagHint": "Etiqueta",
|
||||
"accountKeyType": "Tipo de chave",
|
||||
"sessionExpired": "Sessão expirada",
|
||||
@@ -27,7 +27,7 @@
|
||||
"description": "Title of the dialog when the users current session is invalid/expired"
|
||||
},
|
||||
"pleaseLoginAgain": "Por favor, faça login novamente",
|
||||
"loggingOut": "Desconectando...",
|
||||
"loggingOut": "Saindo...",
|
||||
"timeBasedKeyType": "Baseado no horário (TOTP)",
|
||||
"counterBasedKeyType": "Baseado em um contador (HOTP)",
|
||||
"saveAction": "Salvar",
|
||||
@@ -51,7 +51,7 @@
|
||||
"reportABug": "Informar um problema",
|
||||
"crashAndErrorReporting": "Reporte de erros e falhas",
|
||||
"reportBug": "Informar problema",
|
||||
"emailUsMessage": "Por favor, envie um e-mail para {email}",
|
||||
"emailUsMessage": "Envie um e-mail para {email}",
|
||||
"@emailUsMessage": {
|
||||
"placeholders": {
|
||||
"email": {
|
||||
@@ -59,12 +59,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"contactSupport": "Falar com o suporte",
|
||||
"contactSupport": "Falar com o Suporte",
|
||||
"rateUsOnStore": "Avalie-nos na {storeName}",
|
||||
"blog": "Blog",
|
||||
"merchandise": "Produtos",
|
||||
"verifyPassword": "Verificar senha",
|
||||
"pleaseWait": "Por favor, aguarde...",
|
||||
"pleaseWait": "Aguarde...",
|
||||
"generatingEncryptionKeysTitle": "Gerando chaves de criptografia...",
|
||||
"recreatePassword": "Recriar senha",
|
||||
"recreatePasswordMessage": "O dispositivo atual não é poderoso o suficiente para verificar sua senha, mas podemos regenerar de uma forma que funcione com todos os dispositivos.\n\nPor favor, faça o login usando sua chave de recuperação e recrie sua senha (você pode usar o mesmo novamente se desejar).",
|
||||
@@ -81,10 +81,10 @@
|
||||
"importTypePlainText": "Texto simples",
|
||||
"importTypeEnteEncrypted": "Exportação Ente criptografada",
|
||||
"passwordForDecryptingExport": "Senha para descriptografar a exportação",
|
||||
"passwordEmptyError": "O campo senha não pode estar vazio",
|
||||
"passwordEmptyError": "A senha não pode estar vazia",
|
||||
"importFromApp": "Importar códigos do {appName}",
|
||||
"importGoogleAuthGuide": "Exporte suas contas do Google Authenticator para um QR code usando a opção \"Transferir contas\". Então, usando outro dispositivo, escaneie o QR code.\n\nDica: Você pode usar a câmera do seu notebook para fotografar o QR code.",
|
||||
"importSelectJsonFile": "Selecione o arquivo JSON",
|
||||
"importSelectJsonFile": "Selecionar arquivo JSON",
|
||||
"importSelectAppExport": "Selecione o arquivo de exportação do aplicativo {appName}",
|
||||
"importEnteEncGuide": "Selecione o arquivo JSON criptografado exportado do Ente",
|
||||
"importRaivoGuide": "Use a opção \"Exportar OTPs para arquivo Zip\" nas configurações do Raivo.\n\nExtraia o arquivo zip e importe o arquivo JSON.",
|
||||
@@ -92,7 +92,7 @@
|
||||
"importAegisGuide": "Use a opção \"Exportar cofre\" nas Configurações do Aegis.\n\nSe o seu cofre estiver criptografado, você precisará inserir a senha do cofre para descriptografá-lo.",
|
||||
"import2FasGuide": "Use a opção \"Configurações->Exportar cópia de segurança\" no aplicativo 2FAS.\n\nSe a cópia de segurança estiver criptografada, será necessário inserir a senha para descriptografá-la",
|
||||
"importLastpassGuide": "Use a opção \"Transferir contas\" nas configurações do LastPass Authenticator e pressione \"Exportar contas para arquivo\". Importe o arquivo JSON baixado.",
|
||||
"exportCodes": "Exportar Códigos",
|
||||
"exportCodes": "Exportar códigos",
|
||||
"importLabel": "Importar",
|
||||
"importInstruction": "Por favor, selecione um arquivo que contenha uma lista de códigos no seguinte formato",
|
||||
"importCodeDelimiterInfo": "Os códigos podem ser separados por uma vírgula ou uma nova linha",
|
||||
@@ -114,14 +114,14 @@
|
||||
"general": "Geral",
|
||||
"settings": "Ajustes",
|
||||
"copied": "Copiado",
|
||||
"pleaseTryAgain": "Por favor, tente novamente",
|
||||
"existingUser": "Usuário Existente",
|
||||
"pleaseTryAgain": "Tente de novo",
|
||||
"existingUser": "Usuário existente",
|
||||
"newUser": "Novo no Ente",
|
||||
"delete": "Excluir",
|
||||
"enterYourPasswordHint": "Insira sua senha",
|
||||
"forgotPassword": "Esqueci a senha",
|
||||
"oops": "Opa",
|
||||
"suggestFeatures": "Sugerir funcionalidades",
|
||||
"suggestFeatures": "Sugerir recursos",
|
||||
"faq": "Perguntas frequentes",
|
||||
"faq_q_1": "Quão seguro é o Auth?",
|
||||
"faq_a_1": "Todos os códigos que você faz backup via Auth são armazenados criptografados de ponta a ponta. Isso significa que somente você pode acessar seus códigos. Nossos aplicativos são de código aberto e nossa criptografia foi auditada externamente.",
|
||||
@@ -143,12 +143,12 @@
|
||||
"verify": "Verificar",
|
||||
"verifyEmail": "Verificar e-mail",
|
||||
"enterCodeHint": "Digite o código de 6 dígitos de\nseu aplicativo autenticador",
|
||||
"lostDeviceTitle": "Perdeu seu dispositivo?",
|
||||
"lostDeviceTitle": "Perdeu um dispositivo?",
|
||||
"twoFactorAuthTitle": "Autenticação de dois fatores",
|
||||
"passkeyAuthTitle": "Autenticação via Chave de acesso",
|
||||
"verifyPasskey": "Verificar chave de acesso",
|
||||
"verifyPasskey": "Verificar senha-mestra",
|
||||
"recoverAccount": "Recuperar conta",
|
||||
"enterRecoveryKeyHint": "Digite sua chave de recuperação",
|
||||
"enterRecoveryKeyHint": "Digite a chave de recuperação",
|
||||
"recover": "Recuperar",
|
||||
"contactSupportViaEmailMessage": "Por favor, envie um e-mail para {email} a partir do seu endereço de e-mail registrado",
|
||||
"@contactSupportViaEmailMessage": {
|
||||
@@ -160,7 +160,7 @@
|
||||
},
|
||||
"invalidQRCode": "QR Code inválido",
|
||||
"noRecoveryKeyTitle": "Sem chave de recuperação?",
|
||||
"enterEmailHint": "Insira o seu endereço de e-mail",
|
||||
"enterEmailHint": "Insira o endereço de e-mail",
|
||||
"invalidEmailTitle": "Endereço de e-mail inválido",
|
||||
"invalidEmailMessage": "Por favor, insira um endereço de e-mail válido.",
|
||||
"deleteAccount": "Excluir conta",
|
||||
@@ -175,8 +175,8 @@
|
||||
"moderateStrength": "Moderada",
|
||||
"confirmPassword": "Confirme sua senha",
|
||||
"close": "Fechar",
|
||||
"oopsSomethingWentWrong": "Oops, Algo deu errado.",
|
||||
"selectLanguage": "Selecionar idioma",
|
||||
"oopsSomethingWentWrong": "Opa. Algo deu errado.",
|
||||
"selectLanguage": "Trocar idioma",
|
||||
"language": "Idioma",
|
||||
"social": "Redes sociais",
|
||||
"security": "Segurança",
|
||||
@@ -199,14 +199,14 @@
|
||||
"recoveryKeyCopiedToClipboard": "A chave de recuperação foi copiada para a área de transferência",
|
||||
"recoveryKeyOnForgotPassword": "Caso você esqueça sua senha, a única maneira de recuperar seus dados é com essa chave.",
|
||||
"recoveryKeySaveDescription": "Não armazenamos essa chave, por favor, salve essa chave de 24 palavras em um lugar seguro.",
|
||||
"doThisLater": "Fazer isso mais tarde",
|
||||
"doThisLater": "Fazer isso depois",
|
||||
"saveKey": "Salvar chave",
|
||||
"save": "Salvar",
|
||||
"send": "Enviar",
|
||||
"saveOrSendDescription": "Você deseja salvar isso no seu armazenamento (pasta de downloads por padrão) ou enviá-lo para outros aplicativos?",
|
||||
"saveOnlyDescription": "Você deseja salvar isto no seu armazenamento (pasta de downloads por padrão)?",
|
||||
"back": "Voltar",
|
||||
"createAccount": "Criar uma conta",
|
||||
"createAccount": "Criar conta",
|
||||
"passwordStrength": "Força da senha: {passwordStrengthValue}",
|
||||
"@passwordStrength": {
|
||||
"description": "Text to indicate the password strength",
|
||||
@@ -234,7 +234,7 @@
|
||||
"passwordChangedSuccessfully": "Senha alterada com sucesso",
|
||||
"generatingEncryptionKeys": "Gerando chaves de criptografia...",
|
||||
"continueLabel": "Continuar",
|
||||
"insecureDevice": "Dispositivo não seguro",
|
||||
"insecureDevice": "Dispositivo inseguro",
|
||||
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Desculpe, não foi possível gerar chaves seguras neste dispositivo.\n\npor favor, faça o login com um dispositivo diferente.",
|
||||
"howItWorks": "Como funciona",
|
||||
"ackPasswordLostWarning": "Eu entendo que se eu perder minha senha, posso perder meus dados, já que meus dados são <underline>criptografados de ponta a ponta</underline>.",
|
||||
@@ -257,11 +257,11 @@
|
||||
"recoveryKeyVerifyReason": "Sua chave de recuperação é a única maneira de recuperar suas fotos se você esquecer sua senha. Você pode encontrar sua chave de recuperação em Configurações > Conta.\n\nDigite sua chave de recuperação aqui para verificar se você a salvou corretamente.",
|
||||
"confirmYourRecoveryKey": "Confirme sua chave de recuperação",
|
||||
"confirm": "Confirmar",
|
||||
"emailYourLogs": "Enviar por email seus logs",
|
||||
"emailYourLogs": "Enviar logs por e-mail",
|
||||
"pleaseSendTheLogsTo": "Por favor, envie os logs para \n{toEmail}",
|
||||
"copyEmailAddress": "Copiar endereço de e-mail",
|
||||
"exportLogs": "Exportar logs",
|
||||
"enterYourRecoveryKey": "Digite sua chave de recuperação",
|
||||
"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.",
|
||||
"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",
|
||||
@@ -277,7 +277,7 @@
|
||||
"youAreOnTheLatestVersion": "Você está na versão mais recente",
|
||||
"warning": "Atenção",
|
||||
"exportWarningDesc": "O arquivo exportado contém informações confidenciais. Por favor, armazene-o com segurança.",
|
||||
"iUnderStand": "Eu entendo",
|
||||
"iUnderStand": "Entendo",
|
||||
"@iUnderStand": {
|
||||
"description": "Text for the button to confirm the user understands the warning"
|
||||
},
|
||||
@@ -326,11 +326,11 @@
|
||||
"sorryTheCodeYouveEnteredIsIncorrect": "Desculpe, o código que você inseriu está incorreto",
|
||||
"emailChangedTo": "E-mail alterado para {newEmail}",
|
||||
"authenticationFailedPleaseTryAgain": "Falha na autenticação. Por favor, tente novamente",
|
||||
"authenticationSuccessful": "Autenticação bem-sucedida!",
|
||||
"authenticationSuccessful": "Autenticado!",
|
||||
"twofactorAuthenticationSuccessfullyReset": "Autenticação de dois fatores redefinida com sucesso",
|
||||
"incorrectRecoveryKey": "Chave de recuperação incorreta",
|
||||
"theRecoveryKeyYouEnteredIsIncorrect": "A chave de recuperação inserida está incorreta",
|
||||
"enterPassword": "Insira a senha",
|
||||
"enterPassword": "Inserir senha",
|
||||
"selectExportFormat": "Selecione o formato para exportação",
|
||||
"exportDialogDesc": "As exportações criptografadas ficarão protegidas por uma senha de sua escolha.",
|
||||
"encrypted": "Criptografado",
|
||||
@@ -345,7 +345,7 @@
|
||||
"showLargeIcons": "Mostrar ícones grandes",
|
||||
"shouldHideCode": "Ocultar códigos",
|
||||
"doubleTapToViewHiddenCode": "Você pode tocar duas vezes em uma entrada para ver o código",
|
||||
"focusOnSearchBar": "Foco na pesquisa ao iniciar o aplicativo",
|
||||
"focusOnSearchBar": "Foco na busca ao iniciar o app",
|
||||
"confirmUpdatingkey": "Você tem certeza que deseja atualizar a chave secreta?",
|
||||
"minimizeAppOnCopy": "Minimizar aplicativo ao copiar",
|
||||
"editCodeAuthMessage": "Autenticar para editar o código",
|
||||
@@ -357,7 +357,7 @@
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Não reconhecido. Tente novamente.",
|
||||
"androidBiometricNotRecognized": "Não reconhecido. Tente de novo.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
@@ -385,7 +385,7 @@
|
||||
"@androidDeviceCredentialsSetupDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"goToSettings": "Ir para Configurações",
|
||||
"goToSettings": "Ir para Ajustes",
|
||||
"@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."
|
||||
},
|
||||
@@ -410,13 +410,13 @@
|
||||
"signOutFromOtherDevices": "Terminar sessão em outros dispositivos",
|
||||
"signOutOtherBody": "Se você acha que alguém pode saber sua senha, você pode forçar todos os outros dispositivos que estão com sua conta a desconectar.",
|
||||
"signOutOtherDevices": "Terminar sessão em outros dispositivos",
|
||||
"doNotSignOut": "Não encerrar sessão",
|
||||
"doNotSignOut": "Não sair",
|
||||
"hearUsWhereTitle": "Como você ouviu sobre o Ente? (opcional)",
|
||||
"hearUsExplanation": "Não rastreamos instalações do aplicativo. Seria útil se você nos contasse onde nos encontrou!",
|
||||
"recoveryKeySaved": "Chave de recuperação salva na pasta Downloads!",
|
||||
"waitingForBrowserRequest": "Aguardando solicitação do navegador...",
|
||||
"waitingForVerification": "Esperando por verificação...",
|
||||
"passkey": "Chave de acesso",
|
||||
"passkey": "Senha-mestra",
|
||||
"developerSettingsWarning": "Tem certeza de que deseja modificar as configurações de Desenvolvedor?",
|
||||
"developerSettings": "Configurações de desenvolvedor",
|
||||
"serverEndpoint": "Endpoint do servidor",
|
||||
@@ -429,7 +429,7 @@
|
||||
"pinnedCodeMessage": "{code} foi fixado",
|
||||
"unpinnedCodeMessage": "{code} foi desafixado",
|
||||
"tags": "Etiquetas",
|
||||
"createNewTag": "Criar etiqueta",
|
||||
"createNewTag": "Criar nova etiqueta",
|
||||
"tag": "Etiqueta",
|
||||
"create": "Criar",
|
||||
"editTag": "Editar etiqueta",
|
||||
|
||||
1
auth/lib/l10n/arb/app_te.arb
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -66,8 +66,6 @@ Future<void> initSystemTray() async {
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
initSystemTray().ignore();
|
||||
|
||||
if (PlatformUtil.isDesktop()) {
|
||||
await windowManager.ensureInitialized();
|
||||
await WindowListenerService.instance.init();
|
||||
@@ -77,8 +75,10 @@ void main() async {
|
||||
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||
await windowManager.show();
|
||||
await windowManager.focus();
|
||||
initSystemTray().ignore();
|
||||
});
|
||||
}
|
||||
|
||||
await _runInForeground();
|
||||
await _setupPrivacyScreen();
|
||||
if (Platform.isAndroid) {
|
||||
@@ -132,7 +132,7 @@ Future _runWithLogs(Function() function, {String prefix = ""}) async {
|
||||
}
|
||||
|
||||
void _registerWindowsProtocol() {
|
||||
const kWindowsScheme = 'ente';
|
||||
const kWindowsScheme = 'enteauth';
|
||||
// Register our protocol only on Windows platform
|
||||
if (!kIsWeb && Platform.isWindows) {
|
||||
WindowsProtocolHandler()
|
||||
|
||||
@@ -42,7 +42,7 @@ class PasskeyService {
|
||||
Future<void> openPasskeyPage(BuildContext context) async {
|
||||
try {
|
||||
final jwtToken = await getJwtToken();
|
||||
final url = "https://accounts.ente.io/account-handoff?token=$jwtToken";
|
||||
final url = "https://accounts.ente.io/passkeys?token=$jwtToken";
|
||||
await launchUrlString(
|
||||
url,
|
||||
mode: LaunchMode.externalApplication,
|
||||
|
||||
@@ -266,32 +266,77 @@ class UserService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onPassKeyVerified(BuildContext context, Map response) async {
|
||||
final userPassword = Configuration.instance.getVolatilePassword();
|
||||
if (userPassword == null) throw Exception("volatile password is null");
|
||||
|
||||
await _saveConfiguration(response);
|
||||
|
||||
Widget page;
|
||||
if (Configuration.instance.getEncryptedToken() != null) {
|
||||
await Configuration.instance.decryptSecretsAndGetKeyEncKey(
|
||||
userPassword,
|
||||
Configuration.instance.getKeyAttributes()!,
|
||||
);
|
||||
page = const HomePage();
|
||||
} else {
|
||||
throw Exception("unexpected response during passkey verification");
|
||||
}
|
||||
|
||||
// ignore: unawaited_futures
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return page;
|
||||
Future<dynamic> getTokenForPasskeySession(String sessionID) async {
|
||||
try {
|
||||
final response = await _dio.get(
|
||||
"${_config.getHttpEndpoint()}/users/two-factor/passkeys/get-token",
|
||||
queryParameters: {
|
||||
"sessionID": sessionID,
|
||||
},
|
||||
),
|
||||
(route) => route.isFirst,
|
||||
);
|
||||
);
|
||||
return response.data;
|
||||
} on DioException catch (e) {
|
||||
if (e.response != null) {
|
||||
if (e.response!.statusCode == 404 || e.response!.statusCode == 410) {
|
||||
throw PassKeySessionExpiredError();
|
||||
}
|
||||
if (e.response!.statusCode == 400) {
|
||||
throw PassKeySessionNotVerifiedError();
|
||||
}
|
||||
}
|
||||
rethrow;
|
||||
} catch (e, s) {
|
||||
_logger.severe("unexpected error", e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onPassKeyVerified(BuildContext context, Map response) async {
|
||||
final ProgressDialog dialog =
|
||||
createProgressDialog(context, context.l10n.pleaseWait);
|
||||
await dialog.show();
|
||||
try {
|
||||
final userPassword = _config.getVolatilePassword();
|
||||
await _saveConfiguration(response);
|
||||
if (userPassword == null) {
|
||||
await dialog.hide();
|
||||
// ignore: unawaited_futures
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const PasswordReentryPage();
|
||||
},
|
||||
),
|
||||
(route) => route.isFirst,
|
||||
);
|
||||
} else {
|
||||
Widget page;
|
||||
if (_config.getEncryptedToken() != null) {
|
||||
await _config.decryptSecretsAndGetKeyEncKey(
|
||||
userPassword,
|
||||
_config.getKeyAttributes()!,
|
||||
);
|
||||
page = const HomePage();
|
||||
} else {
|
||||
throw Exception("unexpected response during passkey verification");
|
||||
}
|
||||
await dialog.hide();
|
||||
|
||||
// ignore: unawaited_futures
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return page;
|
||||
},
|
||||
),
|
||||
(route) => route.isFirst,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
_logger.severe(e);
|
||||
await dialog.hide();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> verifyEmail(
|
||||
@@ -316,9 +361,12 @@ class UserService {
|
||||
await dialog.hide();
|
||||
if (response.statusCode == 200) {
|
||||
Widget page;
|
||||
final String passkeySessionID = response.data["passkeySessionID"];
|
||||
final String twoFASessionID = response.data["twoFactorSessionID"];
|
||||
if (twoFASessionID.isNotEmpty) {
|
||||
page = TwoFactorAuthenticationPage(twoFASessionID);
|
||||
} else if (passkeySessionID.isNotEmpty) {
|
||||
page = PasskeyPage(passkeySessionID);
|
||||
} else {
|
||||
await _saveConfiguration(response);
|
||||
if (Configuration.instance.getEncryptedToken() != null) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class CodeDisplayStore {
|
||||
if (code.hasError) continue;
|
||||
tags.addAll(code.display.tags);
|
||||
}
|
||||
return tags.toList();
|
||||
return tags.toList()..sort();
|
||||
}
|
||||
|
||||
Future<void> showDeleteTagDialog(BuildContext context, String tag) async {
|
||||
|
||||
@@ -33,7 +33,7 @@ enum ButtonType {
|
||||
|
||||
Color defaultButtonColor(EnteColorScheme colorScheme) {
|
||||
if (isPrimary) {
|
||||
return colorScheme.primary500;
|
||||
return colorScheme.primary400;
|
||||
}
|
||||
if (isSecondary) {
|
||||
return colorScheme.fillFaint;
|
||||
|
||||
@@ -238,6 +238,8 @@ class _HomePageState extends State<HomePage> {
|
||||
title: !_showSearchBox
|
||||
? const Text('Ente Auth')
|
||||
: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
focusNode: searchInputFocusNode,
|
||||
autofocus: _searchText.isEmpty,
|
||||
controller: _textController,
|
||||
|
||||
@@ -2,12 +2,14 @@ import 'dart:convert';
|
||||
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/core/errors.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/models/account/two_factor.dart';
|
||||
import 'package:ente_auth/services/user_service.dart';
|
||||
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
||||
import 'package:ente_auth/ui/components/models/button_type.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/toast_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
@@ -41,13 +43,38 @@ class _PasskeyPageState extends State<PasskeyPage> {
|
||||
|
||||
Future<void> launchPasskey() async {
|
||||
await launchUrlString(
|
||||
"https://accounts.ente.io/passkeys/flow?"
|
||||
"https://accounts.ente.io/passkeys/verify?"
|
||||
"passkeySessionID=${widget.sessionID}"
|
||||
"&redirect=enteauth://passkey",
|
||||
"&redirect=enteauth://passkey"
|
||||
"&clientPackage=io.ente.auth",
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> checkStatus() async {
|
||||
late dynamic response;
|
||||
try {
|
||||
response = await UserService.instance
|
||||
.getTokenForPasskeySession(widget.sessionID);
|
||||
} on PassKeySessionNotVerifiedError {
|
||||
showToast(context, context.l10n.passKeyPendingVerification);
|
||||
return;
|
||||
} on PassKeySessionExpiredError {
|
||||
await showErrorDialog(
|
||||
context,
|
||||
context.l10n.loginSessionExpired,
|
||||
context.l10n.loginSessionExpiredDetails,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
} catch (e, s) {
|
||||
_logger.severe("failed to check status", e, s);
|
||||
showGenericErrorDialog(context: context).ignore();
|
||||
return;
|
||||
}
|
||||
await UserService.instance.onPassKeyVerified(context, response);
|
||||
}
|
||||
|
||||
Future<void> _handleDeeplink(String? link) async {
|
||||
if (!context.mounted ||
|
||||
Configuration.instance.hasConfiguredAccount() ||
|
||||
@@ -59,8 +86,20 @@ class _PasskeyPageState extends State<PasskeyPage> {
|
||||
}
|
||||
try {
|
||||
if (mounted && link.toLowerCase().startsWith("enteauth://passkey")) {
|
||||
final String? uri = Uri.parse(link).queryParameters['response'];
|
||||
String base64String = uri!.toString();
|
||||
if (Configuration.instance.isLoggedIn()) {
|
||||
_logger.info('ignored deeplink: already configured');
|
||||
showToast(context, 'Account is already configured.');
|
||||
return;
|
||||
}
|
||||
final parsedUri = Uri.parse(link);
|
||||
final sessionID = parsedUri.queryParameters['passkeySessionID'];
|
||||
if (sessionID != widget.sessionID) {
|
||||
showToast(context, "Session ID mismatch");
|
||||
_logger.warning('ignored deeplink: sessionID mismatch');
|
||||
return;
|
||||
}
|
||||
final String? authResponse = parsedUri.queryParameters['response'];
|
||||
String base64String = authResponse!.toString();
|
||||
while (base64String.length % 4 != 0) {
|
||||
base64String += '=';
|
||||
}
|
||||
@@ -118,9 +157,23 @@ class _PasskeyPageState extends State<PasskeyPage> {
|
||||
const SizedBox(height: 16),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
labelText: context.l10n.verifyPasskey,
|
||||
labelText: context.l10n.tryAgain,
|
||||
onTap: () => launchPasskey(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.secondary,
|
||||
labelText: context.l10n.checkStatus,
|
||||
onTap: () async {
|
||||
try {
|
||||
await checkStatus();
|
||||
} catch (e) {
|
||||
debugPrint('failed to check status %e');
|
||||
showGenericErrorDialog(context: context).ignore();
|
||||
}
|
||||
},
|
||||
shouldSurfaceExecutionStates: true,
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(30)),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
|
||||
@@ -139,7 +139,10 @@ Future<int?> _process2FasExportFile(
|
||||
for (var item in decodedServices) {
|
||||
var kind = item['otp']['tokenType'];
|
||||
var account = item['otp']['account'] ?? '';
|
||||
var issuer = item['otp']['issuer'] ?? item['name'] ?? '';
|
||||
var issuer = item['otp']['issuer'];
|
||||
if (issuer == null || (issuer as String).isEmpty) {
|
||||
issuer = item['name'] ?? '';
|
||||
}
|
||||
var algorithm = item['otp']['algorithm'];
|
||||
var secret = item['secret'];
|
||||
var timer = item['otp']['period'];
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'dart:typed_data';
|
||||
import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/models/user_details.dart';
|
||||
import 'package:ente_auth/services/auth_feature_flag.dart';
|
||||
import 'package:ente_auth/services/local_authentication_service.dart';
|
||||
import 'package:ente_auth/services/passkey_service.dart';
|
||||
import 'package:ente_auth/services/user_service.dart';
|
||||
@@ -66,20 +65,17 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
||||
// We don't know if the user can disable MFA yet, so we fetch the info
|
||||
UserService.instance.getUserDetailsV2().ignore();
|
||||
}
|
||||
final bool isInternalUser =
|
||||
FeatureFlagService.instance.isInternalUserOrDebugBuild();
|
||||
children.addAll([
|
||||
if (isInternalUser) sectionOptionSpacing,
|
||||
if (isInternalUser)
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.passkey,
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async => await onPasskeyClick(context),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.passkey,
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async => await onPasskeyClick(context),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
|
||||
@@ -34,7 +34,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
"Debug" "Profile" "Release")
|
||||
endif()
|
||||
|
||||
# Compilation ui.settings that should be applied to most targets.
|
||||
# Compilation settings that should be applied to most targets.
|
||||
#
|
||||
# Be cautious about adding new options here, as plugins use this function by
|
||||
# default. In most cases, you should add new options to specific targets instead
|
||||
@@ -66,8 +66,8 @@ add_executable(${BINARY_NAME}
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
)
|
||||
|
||||
# Apply the standard set of build ui.settings. This can be removed for applications
|
||||
# that need different build ui.settings.
|
||||
# Apply the standard set of build settings. This can be removed for applications
|
||||
# that need different build settings.
|
||||
apply_standard_settings(${BINARY_NAME})
|
||||
|
||||
# Add dependency libraries. Add any application-specific dependencies here.
|
||||
@@ -86,6 +86,7 @@ set_target_properties(${BINARY_NAME}
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||
)
|
||||
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
# them to the application.
|
||||
include(flutter/generated_plugins.cmake)
|
||||
@@ -122,6 +123,12 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||
COMPONENT Runtime)
|
||||
endforeach(bundled_library)
|
||||
|
||||
# Copy the native assets provided by the build.dart from all packages.
|
||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
|
||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||
# from a previous install.
|
||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||
|
||||
@@ -63,7 +63,7 @@ static void my_application_activate(GApplication *application)
|
||||
}
|
||||
|
||||
gtk_window_set_default_size(window, 1280, 720);
|
||||
gtk_widget_realize(GTK_WIDGET(window));
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
|
||||
@@ -73,6 +73,7 @@ static void my_application_activate(GApplication *application)
|
||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
||||
|
||||
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||
gtk_widget_hide(GTK_WIDGET(window));
|
||||
|
||||
gtk_widget_grab_focus(GTK_WIDGET(view));
|
||||
}
|
||||
@@ -98,6 +99,26 @@ static gboolean my_application_local_command_line(GApplication *application, gch
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Implements GApplication::startup.
|
||||
static void my_application_startup(GApplication *application)
|
||||
{
|
||||
// MyApplication* self = MY_APPLICATION(object);
|
||||
|
||||
// Perform any actions required at application startup.
|
||||
|
||||
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
|
||||
}
|
||||
|
||||
// Implements GApplication::shutdown.
|
||||
static void my_application_shutdown(GApplication *application)
|
||||
{
|
||||
// MyApplication* self = MY_APPLICATION(object);
|
||||
|
||||
// Perform any actions required at application shutdown.
|
||||
|
||||
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
|
||||
}
|
||||
|
||||
// Implements GObject::dispose.
|
||||
static void my_application_dispose(GObject *object)
|
||||
{
|
||||
@@ -110,6 +131,8 @@ static void my_application_class_init(MyApplicationClass *klass)
|
||||
{
|
||||
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
|
||||
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
||||
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
||||
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,3 +27,6 @@ include:
|
||||
- libffi.so.8
|
||||
- libtiff.so.5
|
||||
- libjpeg.so.8
|
||||
|
||||
supported_mime_type:
|
||||
- x-scheme-handler/enteauth
|
||||
@@ -31,4 +31,4 @@ categories:
|
||||
startup_notify: false
|
||||
|
||||
supported_mime_type:
|
||||
- x-scheme-handler/ente
|
||||
- x-scheme-handler/enteauth
|
||||
|
||||
@@ -28,4 +28,4 @@ categories:
|
||||
startup_notify: false
|
||||
|
||||
supported_mime_type:
|
||||
- x-scheme-handler/ente
|
||||
- x-scheme-handler/enteauth
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>otpauth</string>
|
||||
<string>enteauth</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
@@ -45,10 +45,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: archive
|
||||
sha256: "0763b45fa9294197a2885c8567927e2830ade852e5c896fd4ab7e0e348d0f373"
|
||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
version: "3.6.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -117,10 +117,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
version: "4.0.2"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -133,18 +133,18 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22"
|
||||
sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.9"
|
||||
version: "2.4.11"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799"
|
||||
sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.0"
|
||||
version: "7.3.1"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -293,9 +293,9 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/desktop_webview_window"
|
||||
ref: fix-webkit-version
|
||||
resolved-ref: fe2223e4edfecdbb3a97bb9e3ced73db4ae9d979
|
||||
url: "https://github.com/ente-io/flutter-desktopwebview-fork"
|
||||
ref: main
|
||||
resolved-ref: "726d8281a244d56ab36e843f0427c48de6d9cc56"
|
||||
url: "https://github.com/MixinNetwork/flutter-plugins"
|
||||
source: git
|
||||
version: "0.2.4"
|
||||
device_info_plus:
|
||||
@@ -415,10 +415,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_saver
|
||||
sha256: bdebc720e17b3e01aba59da69b6d47020a7e5ba7d5c75bd9194f9618d5f16ef4
|
||||
sha256: d375b351e3331663abbaf99747abd72f159260c58fbbdbca9f926f02c01bdc48
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.12"
|
||||
version: "0.2.13"
|
||||
fixnum:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -444,10 +444,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_bloc
|
||||
sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
|
||||
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.1.5"
|
||||
version: "8.1.6"
|
||||
flutter_context_menu:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -586,59 +586,59 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
|
||||
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.19"
|
||||
version: "2.0.20"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685
|
||||
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.0"
|
||||
version: "9.2.2"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
path: flutter_secure_storage_linux
|
||||
ref: patch-1
|
||||
resolved-ref: da8ab43bc51c8c3249a261c33b27aa6f018f819b
|
||||
url: "https://github.com/prateekmedia/flutter_secure_storage.git"
|
||||
ref: develop
|
||||
resolved-ref: cb30953edc029dc4059b72700270b4cd3a3afade
|
||||
url: "https://github.com/mogol/flutter_secure_storage.git"
|
||||
source: git
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
flutter_secure_storage_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_macos
|
||||
sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c
|
||||
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.1.2"
|
||||
flutter_secure_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_platform_interface
|
||||
sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e"
|
||||
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "1.1.2"
|
||||
flutter_secure_storage_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_web
|
||||
sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20"
|
||||
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.1"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108"
|
||||
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.1.2"
|
||||
flutter_slidable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -685,10 +685,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluttertoast
|
||||
sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66"
|
||||
sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.2.5"
|
||||
version: "8.2.6"
|
||||
freezed_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -725,10 +725,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: gradient_borders
|
||||
sha256: "69eeaff519d145a4c6c213ada1abae386bcc8981a4970d923e478ce7ba19e309"
|
||||
sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -757,10 +757,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hashlib_codecs
|
||||
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
|
||||
sha256: a1c7b5d89ff29e81fd8e8c0b35966db4c935e149fc4ebe1ebf71e358c15863ab
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.4.0"
|
||||
hex:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -805,18 +805,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
|
||||
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.7"
|
||||
version: "4.2.0"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.18.1"
|
||||
version: "0.19.0"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -853,26 +853,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.0"
|
||||
version: "10.0.4"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.3"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.1"
|
||||
lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -893,18 +893,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth_android
|
||||
sha256: e0e5b1ea247c5a0951c13a7ee13dc1beae69750e6a2e1910d1ed6a3cd4d56943
|
||||
sha256: "48dfb2d954da8ef6a77adfc93a29998f7729e9308eaa817e91dea4500317b2c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.38"
|
||||
version: "1.0.39"
|
||||
local_auth_darwin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: local_auth_darwin
|
||||
sha256: "33381a15b0de2279523eca694089393bb146baebdce72a404555d03174ebc1e9"
|
||||
sha256: e424ebf90d5233452be146d4a7da4bcd7a70278b67791592f3fde1bda8eef9e2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
version: "1.3.1"
|
||||
local_auth_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -957,10 +957,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.12.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -973,10 +973,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: mocktail
|
||||
sha256: c4b5007d91ca4f67256e720cb1b6d704e79a510183a12fa551021f652577dce6
|
||||
sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
version: "1.0.4"
|
||||
modal_bottom_sheet:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1085,18 +1085,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
|
||||
sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.2.5"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1141,10 +1141,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1157,10 +1157,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "79fbafed02cfdbe85ef3fd06c7f4bc2cbcba0177e61b765264853d4253b21744"
|
||||
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.9.0"
|
||||
version: "3.9.1"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1205,10 +1205,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
|
||||
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.3"
|
||||
version: "1.3.0"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1245,18 +1245,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry
|
||||
sha256: e572d33a3ff1d69549f33ee828a8ff514047d43ca8eea4ab093d72461205aa3e
|
||||
sha256: "57514bc72d441ffdc463f498d6886aa586a2494fa467a1eb9d649c28010d7ee3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.20.1"
|
||||
version: "7.20.2"
|
||||
sentry_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sentry_flutter
|
||||
sha256: ac8cf6bb849f3560353ae33672e17b2713809a4e8de0d3cf372e9e9c42013757
|
||||
sha256: "9723d58470ca43a360681ddd26abb71ca7b815f706bc8d3747afd054cf639ded"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.20.1"
|
||||
version: "7.20.2"
|
||||
share_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1285,18 +1285,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
|
||||
sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.2.3"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
|
||||
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.5"
|
||||
version: "2.4.0"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1341,10 +1341,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
|
||||
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
version: "2.0.0"
|
||||
shortid:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1370,10 +1370,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sodium_libs
|
||||
sha256: f7f6719b7ab3e8512ce7a5ecd7bc8d865482431cdd5a07a46b55b13c152b54e1
|
||||
sha256: "441444f6f433032bae3444c2ef5ed2cf5bc0def77f104abdff20aedcf79a7c7a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1+1"
|
||||
version: "2.2.1+5"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1411,10 +1411,10 @@ packages:
|
||||
description:
|
||||
path: sqflite
|
||||
ref: HEAD
|
||||
resolved-ref: f281785e12e8b1abf2f9d41a587fc83d810724cf
|
||||
resolved-ref: "3309d399dd7d695bbfa7c05f643bb16765cef4ee"
|
||||
url: "https://github.com/tekartik/sqflite"
|
||||
source: git
|
||||
version: "2.3.3"
|
||||
version: "2.3.3+1"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1435,18 +1435,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3
|
||||
sha256: "1abbeb84bf2b1a10e5e1138c913123c8aa9d83cd64e5f9a0dd847b3c83063202"
|
||||
sha256: b384f598b813b347c5a7e5ffad82cbaff1bec3d1561af267041e66f6f0899295
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
version: "2.4.3"
|
||||
sqlite3_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqlite3_flutter_libs
|
||||
sha256: fb2a106a2ea6042fe57de2c47074cc31539a941819c91e105b864744605da3f5
|
||||
sha256: "9f89a7e7dc36eac2035808427eba1c3fbd79e59c3a22093d8dace6d36b1fe89e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.21"
|
||||
version: "0.5.23"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1523,10 +1523,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.1"
|
||||
version: "0.7.0"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1547,10 +1547,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: tray_manager
|
||||
sha256: e0ac9a88b2700f366b8629b97e8663b6ef450a2f169560a685dc167bfe9c9c29
|
||||
sha256: c9a63fd88bd3546287a7eb8ccc978d707eef82c775397af17dda3a4f4c039e64
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
version: "0.2.3"
|
||||
tuple:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1579,26 +1579,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.6"
|
||||
version: "6.3.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775"
|
||||
sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.1"
|
||||
version: "6.3.3"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
|
||||
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.5"
|
||||
version: "6.3.0"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1611,10 +1611,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.2.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1683,10 +1683,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
version: "14.2.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1703,22 +1703,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "24301d8c293ce6fe327ffe6f59d8fd8834735f0ec36e4fd383ec7ff8a64aa078"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
|
||||
sha256: a2d56211ee4d35d9b344d9d4ce60f362e4f5d1aafb988302906bd732bc731276
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.5"
|
||||
version: "3.0.0"
|
||||
win32:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: win32
|
||||
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
|
||||
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.0"
|
||||
version: "5.5.1"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1731,10 +1739,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: window_manager
|
||||
sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494
|
||||
sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.8"
|
||||
version: "0.3.9"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1768,5 +1776,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.3.0 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
||||
dart: ">=3.4.0 <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 3.0.8+308
|
||||
version: 3.0.12+312
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -20,8 +20,8 @@ dependencies:
|
||||
convert: ^3.1.1
|
||||
desktop_webview_window:
|
||||
git:
|
||||
url: https://github.com/ente-io/flutter-desktopwebview-fork
|
||||
ref: fix-webkit-version
|
||||
url: https://github.com/MixinNetwork/flutter-plugins
|
||||
ref: main
|
||||
path: packages/desktop_webview_window
|
||||
device_info_plus: ^9.1.1
|
||||
dio: ^5.4.0
|
||||
@@ -64,7 +64,7 @@ dependencies:
|
||||
google_nav_bar: ^5.0.5 #supported
|
||||
gradient_borders: ^1.0.0
|
||||
http: ^1.1.0
|
||||
intl: ^0.18.0
|
||||
intl: ^0.19.0
|
||||
json_annotation: ^4.5.0
|
||||
local_auth: ^2.2.0
|
||||
local_auth_android: ^1.0.37
|
||||
@@ -102,13 +102,13 @@ dependencies:
|
||||
url_launcher: ^6.1.5
|
||||
uuid: ^4.2.2
|
||||
win32: ^5.1.1
|
||||
window_manager: ^0.3.8
|
||||
window_manager: ^0.3.9
|
||||
|
||||
dependency_overrides:
|
||||
flutter_secure_storage_linux:
|
||||
git:
|
||||
url: https://github.com/prateekmedia/flutter_secure_storage.git
|
||||
ref: patch-1
|
||||
url: https://github.com/mogol/flutter_secure_storage.git
|
||||
ref: develop
|
||||
path: flutter_secure_storage_linux
|
||||
dev_dependencies:
|
||||
build_runner: ^2.1.11
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 133 KiB |
@@ -5,6 +5,8 @@
|
||||
|
||||
endpoint:
|
||||
api: "http://localhost:8080"
|
||||
# Endpoint for the account service for passkey
|
||||
accounts: "http://localhost:3001"
|
||||
|
||||
log:
|
||||
http: false # log status code & time taken by requests
|
||||
|
||||
@@ -71,12 +71,15 @@ func NewClient(p Params) *Client {
|
||||
restClient: enteAPI,
|
||||
downloadClient: resty.New().
|
||||
SetRetryCount(3).
|
||||
SetRetryWaitTime(5 * time.Second).
|
||||
SetRetryMaxWaitTime(10 * time.Second).
|
||||
SetRetryWaitTime(10 * time.Second).
|
||||
SetRetryMaxWaitTime(20 * time.Second).
|
||||
AddRetryCondition(func(r *resty.Response, err error) bool {
|
||||
shouldRetry := r.StatusCode() == 429 || r.StatusCode() > 500
|
||||
shouldRetry := r.StatusCode() == 429 || r.StatusCode() >= 500
|
||||
if shouldRetry {
|
||||
log.Printf("retrying download due to %d code", r.StatusCode())
|
||||
amxRequestID := r.Header().Get("X-Amz-Request-Id")
|
||||
cfRayID := r.Header().Get("CF-Ray")
|
||||
wasabiRefID := r.Header().Get("X-Wasabi-Cm-Reference-Id")
|
||||
log.Printf("Retry scheduled. error statusCode: %d, X-Amz-Request-Id: %s, CF-Ray: %s, X-Wasabi-Cm-Reference-Id: %s", r.StatusCode(), amxRequestID, cfRayID, wasabiRefID)
|
||||
}
|
||||
return shouldRetry
|
||||
}),
|
||||
|
||||
@@ -161,3 +161,22 @@ func (c *Client) VerifyTotp(
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (c *Client) CheckPasskeyStatus(ctx context.Context,
|
||||
sessionID string) (*AuthorizationResponse, error) {
|
||||
var res AuthorizationResponse
|
||||
r, err := c.restClient.R().
|
||||
SetContext(ctx).
|
||||
SetResult(&res).
|
||||
Get("/users/two-factor/passkeys/get-token?sessionID=" + sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.IsError() {
|
||||
return nil, &ApiError{
|
||||
StatusCode: r.StatusCode(),
|
||||
Message: r.String(),
|
||||
}
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ type AuthorizationResponse struct {
|
||||
EncryptedToken string `json:"encryptedToken,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
TwoFactorSessionID string `json:"twoFactorSessionID"`
|
||||
PassKeySessionID string `json:"passkeySessionID"`
|
||||
// SrpM2 is sent only if the user is logging via SRP
|
||||
// SrpM2 is the SRP M2 value aka the proof that the server has the verifier
|
||||
SrpM2 *string `json:"srpM2,omitempty"`
|
||||
@@ -45,3 +46,7 @@ type AuthorizationResponse struct {
|
||||
func (a *AuthorizationResponse) IsMFARequired() bool {
|
||||
return a.TwoFactorSessionID != ""
|
||||
}
|
||||
|
||||
func (a *AuthorizationResponse) IsPasskeyRequired() bool {
|
||||
return a.PassKeySessionID != ""
|
||||
}
|
||||
|
||||
@@ -38,6 +38,17 @@ func GetUserInput(label string) (string, error) {
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func WaitForEnter(prompt string) error {
|
||||
fmt.Println(prompt)
|
||||
// Create a new reader from standard input.
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
_, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAppType() api.App {
|
||||
for {
|
||||
app, err := GetUserInput("Enter app type (default: photos)")
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var AppVersion = "0.1.14"
|
||||
var AppVersion = "0.1.16"
|
||||
|
||||
func main() {
|
||||
cliDBPath, err := GetCLIConfigPath()
|
||||
@@ -75,6 +75,10 @@ func main() {
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(os.Args) == 1 {
|
||||
// If no arguments are passed, show help
|
||||
os.Args = append(os.Args, "help")
|
||||
}
|
||||
cmd.Execute(&ctrl, AppVersion)
|
||||
}
|
||||
|
||||
@@ -85,6 +89,7 @@ func initConfig(cliConfigPath string) {
|
||||
viper.AddConfigPath(".") // optionally look for config in the working directory
|
||||
|
||||
viper.SetDefault("endpoint.api", constants.EnteApiUrl)
|
||||
viper.SetDefault("endpoint.accounts", constants.EnteAccountUrl)
|
||||
viper.SetDefault("log.http", false)
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
|
||||
@@ -58,6 +58,10 @@ func (c *ClICtrl) AddAccount(cxt context.Context) {
|
||||
if authResponse.IsMFARequired() {
|
||||
authResponse, flowErr = c.validateTOTP(cxt, authResponse)
|
||||
}
|
||||
|
||||
if authResponse.IsPasskeyRequired() {
|
||||
authResponse, flowErr = c.verifyPassKey(cxt, authResponse)
|
||||
}
|
||||
if authResponse.EncryptedToken == "" || authResponse.KeyAttributes == nil {
|
||||
log.Fatalf("missing key attributes or token.\nNote: Please use the mobile,web or desktop app to create a new account.\nIf you are trying to login to an existing account, report a bug.")
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"github.com/ente-io/cli/internal/api"
|
||||
eCrypto "github.com/ente-io/cli/internal/crypto"
|
||||
"github.com/ente-io/cli/pkg/model"
|
||||
"github.com/ente-io/cli/utils/browser"
|
||||
"github.com/ente-io/cli/utils/encoding"
|
||||
"github.com/spf13/viper"
|
||||
"log"
|
||||
|
||||
"github.com/kong/go-srp"
|
||||
@@ -139,6 +141,31 @@ func (c *ClICtrl) validateTOTP(ctx context.Context, authResp *api.AuthorizationR
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClICtrl) verifyPassKey(ctx context.Context, authResp *api.AuthorizationResponse) (*api.AuthorizationResponse, error) {
|
||||
if !authResp.IsPasskeyRequired() {
|
||||
return authResp, nil
|
||||
}
|
||||
baseAccountUrl := viper.GetString("endpoint.accounts")
|
||||
passkeyAuthUrl := fmt.Sprintf("%s/passkeys/verify?passkeySessionID=%s&redirect=ente-cli://passkey&clientPackage=io.ente.photos", baseAccountUrl, authResp.PassKeySessionID)
|
||||
fmt.Printf("Open this url in browser to verify passkey: %s\n", passkeyAuthUrl)
|
||||
err := browser.OpenURL(passkeyAuthUrl)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to open browser: %v\n", err)
|
||||
}
|
||||
for {
|
||||
err = internal.WaitForEnter("Press enter once you have completed the passkey verification")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totpResp, err := c.Client.CheckPasskeyStatus(ctx, authResp.PassKeySessionID)
|
||||
if err != nil {
|
||||
log.Printf("failed to verify %v", err)
|
||||
continue
|
||||
}
|
||||
return totpResp, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClICtrl) validateEmail(ctx context.Context, email string) (*api.AuthorizationResponse, error) {
|
||||
err := c.Client.SendEmailOTP(ctx, email)
|
||||
if err != nil {
|
||||
|
||||
48
cli/utils/browser/browser.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package browser
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// https://stackoverflow.com/questions/39320371/how-start-web-server-to-open-page-in-browser-in-golang
|
||||
// openURL opens the specified URL in the default browser of the user.
|
||||
func OpenURL(url string) error {
|
||||
var cmd string
|
||||
var args []string
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = "cmd"
|
||||
args = []string{"/c", "start"}
|
||||
case "darwin":
|
||||
cmd = "open"
|
||||
args = []string{url}
|
||||
default: // "linux", "freebsd", "openbsd", "netbsd"
|
||||
// Check if running under WSL
|
||||
if isWSL() {
|
||||
// Use 'cmd.exe /c start' to open the URL in the default Windows browser
|
||||
cmd = "cmd.exe"
|
||||
args = []string{"/c", "start", url}
|
||||
} else {
|
||||
// Use xdg-open on native Linux environments
|
||||
cmd = "xdg-open"
|
||||
args = []string{url}
|
||||
}
|
||||
}
|
||||
if len(args) > 1 {
|
||||
// args[0] is used for 'start' command argument, to prevent issues with URLs starting with a quote
|
||||
args = append(args[:1], append([]string{""}, args[1:]...)...)
|
||||
}
|
||||
return exec.Command(cmd, args...).Start()
|
||||
}
|
||||
|
||||
// isWSL checks if the Go program is running inside Windows Subsystem for Linux
|
||||
func isWSL() bool {
|
||||
releaseData, err := exec.Command("uname", "-r").Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(strings.ToLower(string(releaseData)), "microsoft")
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
package constants
|
||||
|
||||
const CliDataPath = "/cli-data/"
|
||||
|
||||
const EnteApiUrl = "https://api.ente.io"
|
||||
const EnteAccountUrl = "https://account.ente.io"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: "Release"
|
||||
|
||||
# Build the ente-io/ente's desktop/rc branch and create/update a draft release.
|
||||
# Build the desktop app with code from ente-io/ente and create/update a release.
|
||||
#
|
||||
# For more details, see `docs/release.md` in ente-io/ente.
|
||||
|
||||
@@ -17,9 +17,10 @@ on:
|
||||
#
|
||||
- cron: "45 2 * * 1-6"
|
||||
push:
|
||||
# Run when a tag matching the pattern "v*"" is pushed.
|
||||
# Run when a tag matching the pattern "vd.d.d"" is pushed. Crucially for
|
||||
# us, this excludes the "-rc" tags.
|
||||
tags:
|
||||
- "v*"
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v1.7.1 (Unreleased)
|
||||
## v1.7.2 (Unreleased)
|
||||
|
||||
- .
|
||||
|
||||
## v1.7.1
|
||||
|
||||
- Support for passkeys as a second factor authentication mechanism.
|
||||
- Remember the window size across app restarts.
|
||||
- Revert changes to the Linux icon.
|
||||
- Fix an issue causing deleted items in watched folders to not move to
|
||||
uncategorized.
|
||||
- Fix duplicate file uploads when initializing a folder watch (sometimes).
|
||||
|
||||
## v1.7.0
|
||||
|
||||
|
||||
@@ -53,23 +53,24 @@ This'll trigger the workflow and create a new pre-release. We can edit this to
|
||||
add the release notes, convert it to a release. Once it is marked as latest, the
|
||||
release goes live.
|
||||
|
||||
We are done at this point, and can now create a new pre-release to host
|
||||
We are done at this point, and can now update the other pre-release that hosts
|
||||
subsequent nightly builds.
|
||||
|
||||
1. Update `package.json` in the source repo to use version `1.x.x-rc`, and
|
||||
merge these changes into `main`.
|
||||
|
||||
2. In the release repo:
|
||||
2. In the release repo, delete the existing _nightly_ pre-release, then:
|
||||
|
||||
```sh
|
||||
git tag 1.x.x-rc
|
||||
git push origin 1.x.x-rc
|
||||
```
|
||||
|
||||
3. Once the workflow finishes and the pre-release is created, edit its
|
||||
description to "Nightly builds".
|
||||
3. Start a new run of the workflow (`gh workflow run desktop-release.yml`).
|
||||
|
||||
4. Delete the pre-release for the previous (already released) version.
|
||||
Once the workflow finishes and the 1.x.x-rc pre-release is created, edit its
|
||||
description to "Nightly builds". Subsequent scheduled nightly builds will update
|
||||
this pre-release.
|
||||
|
||||
## Workflow - Extra pre-releases
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ files:
|
||||
extraFiles:
|
||||
- from: build
|
||||
to: resources
|
||||
protocols:
|
||||
- name: Ente
|
||||
schemes: ["ente"]
|
||||
win:
|
||||
target:
|
||||
- target: nsis
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ente",
|
||||
"version": "1.7.1-rc",
|
||||
"version": "1.7.2-rc",
|
||||
"private": true,
|
||||
"description": "Desktop client for Ente Photos",
|
||||
"repository": "github:ente-io/photos-desktop",
|
||||
@@ -55,6 +55,6 @@
|
||||
"typescript": "^5",
|
||||
"typescript-eslint": "8.0.0-alpha.10"
|
||||
},
|
||||
"packageManager": "yarn@1.22.21",
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"productName": "ente"
|
||||
}
|
||||
|
||||
@@ -61,6 +61,103 @@ export const allowWindowClose = (): void => {
|
||||
shouldAllowWindowClose = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* The app's entry point.
|
||||
*
|
||||
* We call this at the end of this file.
|
||||
*/
|
||||
const main = () => {
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
if (!gotTheLock) {
|
||||
app.quit();
|
||||
return;
|
||||
}
|
||||
|
||||
let mainWindow: BrowserWindow | undefined;
|
||||
|
||||
initLogging();
|
||||
logStartupBanner();
|
||||
registerForEnteLinks();
|
||||
// The order of the next two calls is important
|
||||
setupRendererServer();
|
||||
registerPrivilegedSchemes();
|
||||
migrateLegacyWatchStoreIfNeeded();
|
||||
|
||||
/**
|
||||
* Handle an open URL request, but ensuring that we have a mainWindow.
|
||||
*/
|
||||
const handleOpenURLEnsuringWindow = (url: string) => {
|
||||
log.info(`Attempting to handle request to open URL: ${url}`);
|
||||
if (mainWindow) handleEnteLinks(mainWindow, url);
|
||||
else setTimeout(() => handleOpenURLEnsuringWindow(url), 1000);
|
||||
};
|
||||
|
||||
app.on("second-instance", (_, argv: string[]) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
mainWindow.show();
|
||||
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||
mainWindow.focus();
|
||||
}
|
||||
// On Windows and Linux, this is how we get deeplinks.
|
||||
// See: registerForEnteLinks
|
||||
const url = argv.pop();
|
||||
if (url) handleOpenURLEnsuringWindow(url);
|
||||
});
|
||||
|
||||
// Emitted once, when Electron has finished initializing.
|
||||
//
|
||||
// Note that some Electron APIs can only be used after this event occurs.
|
||||
void app.whenReady().then(() => {
|
||||
void (async () => {
|
||||
// Create window and prepare for the renderer.
|
||||
mainWindow = createMainWindow();
|
||||
|
||||
// Setup IPC and streams.
|
||||
const watcher = createWatcher(mainWindow);
|
||||
attachIPCHandlers();
|
||||
attachFSWatchIPCHandlers(watcher);
|
||||
attachLogoutIPCHandler(watcher);
|
||||
registerStreamProtocol();
|
||||
|
||||
// Configure the renderer's environment.
|
||||
const webContents = mainWindow.webContents;
|
||||
setDownloadPath(webContents);
|
||||
allowExternalLinks(webContents);
|
||||
allowAllCORSOrigins(webContents);
|
||||
|
||||
// Start loading the renderer.
|
||||
void mainWindow.loadURL(rendererURL);
|
||||
|
||||
// Continue on with the rest of the startup sequence.
|
||||
Menu.setApplicationMenu(await createApplicationMenu(mainWindow));
|
||||
setupTrayItem(mainWindow);
|
||||
setupAutoUpdater(mainWindow);
|
||||
|
||||
try {
|
||||
await deleteLegacyDiskCacheDirIfExists();
|
||||
await deleteLegacyKeysStoreIfExists();
|
||||
} catch (e) {
|
||||
// Log but otherwise ignore errors during non-critical startup
|
||||
// actions.
|
||||
log.error("Ignoring startup error", e);
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
// This is a macOS only event. Show our window when the user activates the
|
||||
// app, e.g. by clicking on its dock icon.
|
||||
app.on("activate", () => mainWindow?.show());
|
||||
|
||||
app.on("before-quit", () => {
|
||||
if (mainWindow) saveWindowBounds(mainWindow);
|
||||
allowWindowClose();
|
||||
});
|
||||
|
||||
// On macOS, this is how we get deeplinks. See: registerForEnteLinks
|
||||
app.on("open-url", (_, url) => handleOpenURLEnsuringWindow(url));
|
||||
};
|
||||
|
||||
/**
|
||||
* Log a standard startup banner.
|
||||
*
|
||||
@@ -137,6 +234,32 @@ const registerPrivilegedSchemes = () => {
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a handler for deeplinks, for the "ente://" protocol.
|
||||
*
|
||||
* See: [Note: Passkey verification in the desktop app].
|
||||
*
|
||||
* Implementation notes:
|
||||
* - https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app
|
||||
* - This works only when the app is packaged.
|
||||
* - On Windows and Linux, we get the deeplink in the "second-instance" event.
|
||||
* - On macOS, we get the deeplink in the "open-url" event.
|
||||
*/
|
||||
const registerForEnteLinks = () => app.setAsDefaultProtocolClient("ente");
|
||||
|
||||
/** Sibling of {@link registerForEnteLinks}. */
|
||||
const handleEnteLinks = (mainWindow: BrowserWindow, url: string) => {
|
||||
// [Note: Using deeplinks to navigate in desktop app]
|
||||
//
|
||||
// Both
|
||||
//
|
||||
// - our deeplink protocol, and
|
||||
// - the protocol we're using to serve/ our bundled web app
|
||||
//
|
||||
// use the same scheme ("ente://"), so the URL can directly be forwarded.
|
||||
mainWindow.webContents.send("openURL", url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an return the {@link BrowserWindow} that will form our app's UI.
|
||||
*
|
||||
@@ -440,79 +563,5 @@ const deleteLegacyKeysStoreIfExists = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
if (!gotTheLock) {
|
||||
app.quit();
|
||||
return;
|
||||
}
|
||||
|
||||
let mainWindow: BrowserWindow | undefined;
|
||||
|
||||
initLogging();
|
||||
logStartupBanner();
|
||||
// The order of the next two calls is important
|
||||
setupRendererServer();
|
||||
registerPrivilegedSchemes();
|
||||
migrateLegacyWatchStoreIfNeeded();
|
||||
|
||||
app.on("second-instance", () => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
mainWindow.show();
|
||||
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||
mainWindow.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Emitted once, when Electron has finished initializing.
|
||||
//
|
||||
// Note that some Electron APIs can only be used after this event occurs.
|
||||
void app.whenReady().then(() => {
|
||||
void (async () => {
|
||||
// Create window and prepare for the renderer.
|
||||
mainWindow = createMainWindow();
|
||||
|
||||
// Setup IPC and streams.
|
||||
const watcher = createWatcher(mainWindow);
|
||||
attachIPCHandlers();
|
||||
attachFSWatchIPCHandlers(watcher);
|
||||
attachLogoutIPCHandler(watcher);
|
||||
registerStreamProtocol();
|
||||
|
||||
// Configure the renderer's environment.
|
||||
const webContents = mainWindow.webContents;
|
||||
setDownloadPath(webContents);
|
||||
allowExternalLinks(webContents);
|
||||
allowAllCORSOrigins(webContents);
|
||||
|
||||
// Start loading the renderer.
|
||||
void mainWindow.loadURL(rendererURL);
|
||||
|
||||
// Continue on with the rest of the startup sequence.
|
||||
Menu.setApplicationMenu(await createApplicationMenu(mainWindow));
|
||||
setupTrayItem(mainWindow);
|
||||
setupAutoUpdater(mainWindow);
|
||||
|
||||
try {
|
||||
await deleteLegacyDiskCacheDirIfExists();
|
||||
await deleteLegacyKeysStoreIfExists();
|
||||
} catch (e) {
|
||||
// Log but otherwise ignore errors during non-critical startup
|
||||
// actions.
|
||||
log.error("Ignoring startup error", e);
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
// This is a macOS only event. Show our window when the user activates the
|
||||
// app, e.g. by clicking on its dock icon.
|
||||
app.on("activate", () => mainWindow?.show());
|
||||
|
||||
app.on("before-quit", () => {
|
||||
if (mainWindow) saveWindowBounds(mainWindow);
|
||||
allowWindowClose();
|
||||
});
|
||||
};
|
||||
|
||||
// Go for it.
|
||||
main();
|
||||
|
||||
@@ -46,7 +46,12 @@ import {
|
||||
computeCLIPTextEmbeddingIfAvailable,
|
||||
} from "./services/ml-clip";
|
||||
import { computeFaceEmbeddings, detectFaces } from "./services/ml-face";
|
||||
import { encryptionKey, saveEncryptionKey } from "./services/store";
|
||||
import {
|
||||
encryptionKey,
|
||||
lastShownChangelogVersion,
|
||||
saveEncryptionKey,
|
||||
setLastShownChangelogVersion,
|
||||
} from "./services/store";
|
||||
import {
|
||||
clearPendingUploads,
|
||||
listZipItems,
|
||||
@@ -101,11 +106,19 @@ export const attachIPCHandlers = () => {
|
||||
|
||||
ipcMain.handle("selectDirectory", () => selectDirectory());
|
||||
|
||||
ipcMain.handle("encryptionKey", () => encryptionKey());
|
||||
|
||||
ipcMain.handle("saveEncryptionKey", (_, encryptionKey: string) =>
|
||||
saveEncryptionKey(encryptionKey),
|
||||
);
|
||||
|
||||
ipcMain.handle("encryptionKey", () => encryptionKey());
|
||||
ipcMain.handle("lastShownChangelogVersion", () =>
|
||||
lastShownChangelogVersion(),
|
||||
);
|
||||
|
||||
ipcMain.handle("setLastShownChangelogVersion", (_, version: number) =>
|
||||
setLastShownChangelogVersion(version),
|
||||
);
|
||||
|
||||
// - App update
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { safeStorage } from "electron/main";
|
||||
import { safeStorageStore } from "../stores/safe-storage";
|
||||
import { uploadStatusStore } from "../stores/upload-status";
|
||||
import { userPreferences } from "../stores/user-preferences";
|
||||
import { watchStore } from "../stores/watch";
|
||||
|
||||
/**
|
||||
* Clear all stores except user preferences.
|
||||
*
|
||||
* This is useful to reset state when the user logs out.
|
||||
* This function is useful to reset state when the user logs out. User
|
||||
* preferences are preserved since they contain things tied to the person using
|
||||
* the app or other machine specific state not tied to the account they were
|
||||
* using inside the app.
|
||||
*/
|
||||
export const clearStores = () => {
|
||||
safeStorageStore.clear();
|
||||
@@ -32,3 +36,9 @@ export const encryptionKey = (): string | undefined => {
|
||||
const keyBuffer = Buffer.from(b64EncryptedKey, "base64");
|
||||
return safeStorage.decryptString(keyBuffer);
|
||||
};
|
||||
|
||||
export const lastShownChangelogVersion = (): number | undefined =>
|
||||
userPreferences.get("lastShownChangelogVersion");
|
||||
|
||||
export const setLastShownChangelogVersion = (version: number) =>
|
||||
userPreferences.set("lastShownChangelogVersion", version);
|
||||
|
||||
@@ -23,6 +23,12 @@ export const createWatcher = (mainWindow: BrowserWindow) => {
|
||||
const folderPaths = folderWatches().map((watch) => watch.folderPath);
|
||||
|
||||
const watcher = chokidar.watch(folderPaths, {
|
||||
// Don't emit "add" events for matching paths when instantiating the
|
||||
// watch (we do a full disk scan on launch on our own, and also getting
|
||||
// the same events from the watcher causes duplicates).
|
||||
ignoreInitial: true,
|
||||
// Ask the watcher to wait for a the file size to stabilize before
|
||||
// telling us about a new file. By default, it waits for 2 seconds.
|
||||
awaitWriteFinish: true,
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,12 @@ interface UserPreferences {
|
||||
hideDockIcon?: boolean;
|
||||
skipAppVersion?: string;
|
||||
muteUpdateNotificationVersion?: string;
|
||||
/**
|
||||
* The changelog version for which we last showed the "What's new" screen.
|
||||
*
|
||||
* See: [Note: Conditions for showing "What's new"]
|
||||
*/
|
||||
lastShownChangelogVersion?: number;
|
||||
/**
|
||||
* The last position and size of our app's window.
|
||||
*
|
||||
@@ -33,6 +39,7 @@ const userPreferencesSchema: Schema<UserPreferences> = {
|
||||
hideDockIcon: { type: "boolean" },
|
||||
skipAppVersion: { type: "string" },
|
||||
muteUpdateNotificationVersion: { type: "string" },
|
||||
lastShownChangelogVersion: { type: "number" },
|
||||
windowBounds: {
|
||||
properties: {
|
||||
x: { type: "number" },
|
||||
|
||||
@@ -72,15 +72,26 @@ const encryptionKey = () => ipcRenderer.invoke("encryptionKey");
|
||||
const saveEncryptionKey = (encryptionKey: string) =>
|
||||
ipcRenderer.invoke("saveEncryptionKey", encryptionKey);
|
||||
|
||||
const onMainWindowFocus = (cb?: () => void) => {
|
||||
const lastShownChangelogVersion = () =>
|
||||
ipcRenderer.invoke("lastShownChangelogVersion");
|
||||
|
||||
const setLastShownChangelogVersion = (version: number) =>
|
||||
ipcRenderer.invoke("setLastShownChangelogVersion", version);
|
||||
|
||||
const onMainWindowFocus = (cb: (() => void) | undefined) => {
|
||||
ipcRenderer.removeAllListeners("mainWindowFocus");
|
||||
if (cb) ipcRenderer.on("mainWindowFocus", cb);
|
||||
};
|
||||
|
||||
const onOpenURL = (cb: ((url: string) => void) | undefined) => {
|
||||
ipcRenderer.removeAllListeners("openURL");
|
||||
if (cb) ipcRenderer.on("openURL", (_, url: string) => cb(url));
|
||||
};
|
||||
|
||||
// - App update
|
||||
|
||||
const onAppUpdateAvailable = (
|
||||
cb?: ((update: AppUpdate) => void) | undefined,
|
||||
cb: ((update: AppUpdate) => void) | undefined,
|
||||
) => {
|
||||
ipcRenderer.removeAllListeners("appUpdateAvailable");
|
||||
if (cb) {
|
||||
@@ -306,7 +317,10 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
logout,
|
||||
encryptionKey,
|
||||
saveEncryptionKey,
|
||||
lastShownChangelogVersion,
|
||||
setLastShownChangelogVersion,
|
||||
onMainWindowFocus,
|
||||
onOpenURL,
|
||||
|
||||
// - App update
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ yarn dev
|
||||
For an editor, VSCode is a good choice. Also install the Prettier extension for
|
||||
VSCode, and set VSCode to format on save. This way the editor will automatically
|
||||
format and wrap the text using the project's standard, so you can just focus on
|
||||
the content.
|
||||
the content. You can also format without VSCode by using the `yarn pretty`
|
||||
command.
|
||||
|
||||
## Have fun!
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ export const sidebar = [
|
||||
link: "/photos/features/location-tags",
|
||||
},
|
||||
{ text: "Map", link: "/photos/features/map" },
|
||||
{
|
||||
text: "Passkeys",
|
||||
link: "/photos/features/passkeys",
|
||||
},
|
||||
{
|
||||
text: "Public link",
|
||||
link: "/photos/features/public-link",
|
||||
@@ -131,6 +135,10 @@ export const sidebar = [
|
||||
text: "Files not uploading",
|
||||
link: "/photos/troubleshooting/files-not-uploading",
|
||||
},
|
||||
{
|
||||
text: "Missing thumbnails",
|
||||
link: "/photos/troubleshooting/thumbnails",
|
||||
},
|
||||
{
|
||||
text: "Sharing debug logs",
|
||||
link: "/photos/troubleshooting/sharing-logs",
|
||||
|
||||
@@ -97,3 +97,6 @@ your own instead of contacting support to ask them to delete your account.
|
||||
Note that both Ente photos and Ente auth data will be deleted when you delete
|
||||
your account (irrespective of which app you delete it from) since both photos
|
||||
and auth use the same underlying account.
|
||||
|
||||
To know details of how your data is deleted, including when you delete your
|
||||
account, please see https://ente.io/blog/how-ente-deletes-data/.
|
||||
|
||||
61
docs/docs/photos/features/passkeys.md
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: Passkeys
|
||||
description: Using passkeys as a second factor for your Ente account
|
||||
---
|
||||
|
||||
# Passkeys
|
||||
|
||||
Passkeys are a new authentication mechanism that uses strong cryptography built
|
||||
into devices, like Windows Hello or Apple's Touch ID. **You can use passkeys as
|
||||
a second factor to secure your Ente account.**
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Passkeys are the colloquial term for a WebAuthn (Web Authentication)
|
||||
> credentials.
|
||||
>
|
||||
> - More details about why and how are in the Passkeys announcement
|
||||
> [blog post](https://ente.io/blog/introducing-passkeys-on-ente/).
|
||||
> - And to know more technical details about how our passkey verification
|
||||
> works, you can see this
|
||||
> [technical note in our source code](https://github.com/ente-io/ente/blob/main/web/docs/webauthn-passkeys.md).
|
||||
|
||||
## Passkeys and TOTP
|
||||
|
||||
Ente already supports TOTP codes (in fact, we built an
|
||||
[entire app](https://ente.io/auth/) to store them...). Passkeys serve as an
|
||||
alternative 2FA (second factor) mechanism.
|
||||
|
||||
If you add a passkey to your Ente account, it will be used instead of any
|
||||
existing 2FA codes that you have configured (if any).
|
||||
|
||||
## Enabling and disabling passkeys
|
||||
|
||||
Passkeys get enabled if you add one (or more) passkeys to your account.
|
||||
Conversely, passkeys get disabled if you remove all your existing passkeys.
|
||||
|
||||
To add and remove passkeys, use the _Passkey_ option in the settings menu. This
|
||||
will open up _accounts.ente.io_, where you can manage your passkeys.
|
||||
|
||||
## Login with passkeys
|
||||
|
||||
If passkeys are enabled, then _accounts.ente.io_ will automatically open when
|
||||
you log into your Ente account on a new device. Here you can follow the
|
||||
instructions given by the browser to verify your passkey.
|
||||
|
||||
> These instructions different for each browser and device, but generally they
|
||||
> will ask you to use the same mechanism that you used when you created the
|
||||
> passkey to verify it (scanning a QR code, using your fingerprint, pressing the
|
||||
> key on your Yubikey or other security key hardware etc).
|
||||
|
||||
## Recovery
|
||||
|
||||
If you are unable to login with your passkey (e.g. if you have misplaced the
|
||||
hardware key that you used to store your passkey), then you can **recover your
|
||||
account by using your Ente recovery key**.
|
||||
|
||||
During login, press cancel on the browser dialog to verify your passkey, and
|
||||
then select the "Recover two-factor" option in the error message that gets
|
||||
shown. This will take you to a place where you can enter your Ente recovery key
|
||||
and login into your account. Now you can go to the _Passkey_ page to delete the
|
||||
lost passkey and/or add a new one.
|
||||
@@ -9,6 +9,9 @@ The latest version of the Ente Photos desktop app can be downloaded from
|
||||
[ente.io/download](https://ente.io/download). If you're having trouble, please
|
||||
see if any of the following cases apply.
|
||||
|
||||
- [Windows](#windows)
|
||||
- [Linux](#linux)
|
||||
|
||||
## Windows
|
||||
|
||||
If the app stops with an "A JavaScript error occurred in the main process - The
|
||||
@@ -17,12 +20,35 @@ start it, then you might need to install the VC++ runtime from Microsoft.
|
||||
|
||||
This is what the error looks like:
|
||||
|
||||
<div style="border: 1px solid black">
|
||||
|
||||
{width=500px}
|
||||
|
||||
</div>
|
||||
|
||||
You can install the Microsoft VC++ redistributable runtime from here:<br/>
|
||||
https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version
|
||||
|
||||
## AppImages on ARM64 Linux
|
||||
## Linux
|
||||
|
||||
### AppImage desktop integration
|
||||
|
||||
AppImages are not fully standalone, and they require additional steps to enable
|
||||
full "desktop integration":
|
||||
|
||||
- Showing the app icon,
|
||||
- Surfacing the app in the list of installed apps,
|
||||
- Handling redirection after passkey verification.
|
||||
|
||||
All the ways of enabling AppImage desktop integration are mentioned in
|
||||
[AppImage documentation](https://docs.appimage.org/user-guide/run-appimages.html#integrating-appimages-into-the-desktop).
|
||||
|
||||
For example, you can download the
|
||||
[appimaged](https://github.com/probonopd/go-appimage/releases) AppImage, run it,
|
||||
and then download the Ente Photos AppImage into your `~/Downloads` folder.
|
||||
_appimaged_ will then pick it up automatically.
|
||||
|
||||
### AppImages on ARM64
|
||||
|
||||
If you're on an ARM64 machine running Linux, and the AppImages doesn't do
|
||||
anything when you run it, you will need to run the following command on your
|
||||
@@ -42,7 +68,7 @@ details, see the following upstream issues:
|
||||
- libz.so: cannot open shared object file with Ubuntu arm64 -
|
||||
[electron-userland/electron-builder/issues/7835](https://github.com/electron-userland/electron-builder/issues/7835)
|
||||
|
||||
## AppImage says it requires FUSE
|
||||
### AppImage says it requires FUSE
|
||||
|
||||
See
|
||||
[docs.appimage.org](https://docs.appimage.org/user-guide/troubleshooting/fuse.html#the-appimage-tells-me-it-needs-fuse-to-run).
|
||||
@@ -53,7 +79,7 @@ tl;dr; for example, on Ubuntu,
|
||||
sudo apt install libfuse2
|
||||
```
|
||||
|
||||
## Linux SUID error
|
||||
### Linux SUID error
|
||||
|
||||
On some Linux distributions, if you run the AppImage from the CLI, it might fail
|
||||
with the following error:
|
||||
|
||||
@@ -8,10 +8,18 @@ description:
|
||||
|
||||
## Network Issue
|
||||
|
||||
If you are using VPN, please try disabling the VPN or switching provider.
|
||||
If you are using VPN, please try disabling the VPN or switching your provider.
|
||||
|
||||
## Web / Desktop
|
||||
|
||||
### Disable "Faster uploads"
|
||||
|
||||
We use a Cloudflare proxy to speed up uploads
|
||||
([blog post](https://ente.io/blog/tech/making-uploads-faster/)). However, in
|
||||
some network configurations (depending on the ISP) this might prevent uploads
|
||||
from going through, so if you're having trouble with uploads please try after
|
||||
disabling the "Faster uploads" setting in _Preferences > Advanced_.
|
||||
|
||||
### Certain file types are not uploading
|
||||
|
||||
The desktop/web app tries to detect if a particular file is video or image. If
|
||||
|
||||
16
docs/docs/photos/troubleshooting/thumbnails.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: Missing thumbnails
|
||||
description:
|
||||
Troubleshooting when thumbnails are not being generated when uploading
|
||||
images in Ente Photos
|
||||
---
|
||||
|
||||
# Missing thumbnails
|
||||
|
||||
## Black thumbnails
|
||||
|
||||
Users have reported an issue with Firefox which prevents the app from generating
|
||||
thumbnails if the "block canvas fingerprinting" setting in Firefox is enabled
|
||||
(i.e. `privacy.resistFingerprinting` is set to true in `about:config`). That
|
||||
feature blocks access to the canvas, and the app needs the canvas to generate
|
||||
thumbnails.
|
||||
@@ -11,5 +11,5 @@
|
||||
"prettier": "^3",
|
||||
"vitepress": "^1.0.0-rc.45"
|
||||
},
|
||||
"packageManager": "yarn@1.22.21"
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
|
||||
@@ -31,5 +31,5 @@
|
||||
"typescript": "^5",
|
||||
"vite": "^5.2"
|
||||
},
|
||||
"packageManager": "yarn@1.22.21"
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"tabWidth": 4
|
||||
"tabWidth": 4,
|
||||
"proseWrap": "always"
|
||||
}
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
# Cloudflare Workers
|
||||
|
||||
Source code for our [Cloudflare
|
||||
Workers](https://developers.cloudflare.com/workers/).
|
||||
Source code for our
|
||||
[Cloudflare Workers](https://developers.cloudflare.com/workers/).
|
||||
|
||||
Each worker is a self contained directory with its each `package.json`.
|
||||
|
||||
## Deploying
|
||||
|
||||
* Switch to a worker directory, e.g. `cd github-discord-notifier`.
|
||||
- Switch to a worker directory, e.g. `cd github-discord-notifier`.
|
||||
|
||||
* Install dependencies (if needed) with `yarn`
|
||||
- Install dependencies (if needed) with `yarn`
|
||||
|
||||
* Login into wrangler (if needed) using `yarn wrangler login`
|
||||
> If you have previously deployed, then you will have an old `yarn.lock`. In
|
||||
> this case it is safe to delete and recreate using `rm yarn.lock && yarn`.
|
||||
|
||||
* Deploy! `yarn wrangler deploy`
|
||||
- Login into wrangler (if needed) using `yarn wrangler login`
|
||||
|
||||
- Deploy! `yarn wrangler deploy`
|
||||
|
||||
Wrangler is the CLI provided by Cloudflare to manage workers. Apart from
|
||||
deploying, it also allows us to stream logs from running workers by using `yarn
|
||||
wrangler tail`.
|
||||
deploying, it also allows us to stream logs from running workers by using
|
||||
`yarn wrangler tail`.
|
||||
|
||||
## Creating a new worker
|
||||
|
||||
@@ -30,3 +33,12 @@ To import an existing worker from the Cloudflare dashboard, use
|
||||
```sh
|
||||
npm create cloudflare@2 existing-worker-name -- --type pre-existing --existing-script existing-worker-name
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
Attach the tail worker to your worker by adding
|
||||
|
||||
tail_consumers = [{ service = "tail" }]
|
||||
|
||||
in its `wrangler.toml`. Then any `console.(log|warn|error)` statements and
|
||||
uncaught exceptions in your worker will be logged to Grafana.
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
"name": "cast-albums",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240314.0",
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
|
||||
@@ -1,50 +1,72 @@
|
||||
/** Proxy file and thumbnail requests from the cast web app */
|
||||
/** Proxy file and thumbnail requests for the cast web app. */
|
||||
|
||||
export default {
|
||||
async fetch(request: Request) {
|
||||
switch (request.method) {
|
||||
case "GET":
|
||||
return handleGET(request);
|
||||
case "OPTIONS":
|
||||
return handleOPTIONS(request);
|
||||
case "GET":
|
||||
return handleGET(request);
|
||||
default:
|
||||
throw new Error(
|
||||
`HTTP 405 Method Not Allowed: ${request.method}`
|
||||
);
|
||||
console.log(`Unsupported HTTP method ${request.method}`);
|
||||
return new Response(null, { status: 405 });
|
||||
}
|
||||
},
|
||||
} satisfies ExportedHandler;
|
||||
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
"Access-Control-Allow-Headers": "X-Cast-Access-Token",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const isAllowedOrigin = (origin: string | null) => {
|
||||
const allowed = ["cast.ente.io", "cast.ente.sh", "localhost"];
|
||||
|
||||
if (!origin) return false;
|
||||
try {
|
||||
const url = new URL(origin);
|
||||
return allowed.includes(url.hostname);
|
||||
} catch {
|
||||
// origin is likely an invalid URL
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleGET = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
const urlParams = new URLSearchParams(url.search);
|
||||
const token =
|
||||
request.headers.get("X-Cast-Access-Token") ??
|
||||
urlParams.get("castToken");
|
||||
|
||||
const fileID = urlParams.get("fileID");
|
||||
const fileID = url.searchParams.get("fileID");
|
||||
if (!fileID) return new Response(null, { status: 400 });
|
||||
|
||||
let castToken = request.headers.get("X-Cast-Access-Token");
|
||||
if (!castToken) {
|
||||
console.warn("Using deprecated castToken query param");
|
||||
castToken = url.searchParams.get("castToken");
|
||||
}
|
||||
|
||||
if (!castToken) {
|
||||
console.error("No cast token provided");
|
||||
return new Response(null, { status: 400 });
|
||||
}
|
||||
|
||||
const pathname = url.pathname;
|
||||
const params = new URLSearchParams({ castToken });
|
||||
|
||||
let response = await fetch(
|
||||
`https://api.ente.io/cast/files${pathname}${fileID}?castToken=${token}`
|
||||
`https://api.ente.io/cast/files${pathname}${fileID}?${params.toString()}`
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
response = new Response(response.body, response);
|
||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
return response;
|
||||
};
|
||||
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
let corsHeaders: Record<string, string> = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET,OPTIONS",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
};
|
||||
|
||||
const acrh = request.headers.get("Access-Control-Request-Headers");
|
||||
if (acrh) {
|
||||
corsHeaders["Access-Control-Allow-Headers"] = acrh;
|
||||
}
|
||||
|
||||
return new Response("", { headers: corsHeaders });
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src/**/*.ts"] }
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src"] }
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
name = "cast-albums"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-03-14"
|
||||
compatibility_date = "2024-06-14"
|
||||
|
||||
[[routes]]
|
||||
pattern = "cast-albums.ente.io"
|
||||
zone_name = "ente.io"
|
||||
custom_domain = true
|
||||
routes = [
|
||||
{ pattern = "cast-albums.ente.io", custom_domain = true }
|
||||
]
|
||||
|
||||
tail_consumers = [
|
||||
{ service = "tail" }
|
||||
]
|
||||
|
||||
10
infra/workers/files/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "files",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
102
infra/workers/files/src/index.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
/** Proxy requests for files. */
|
||||
|
||||
export default {
|
||||
async fetch(request: Request) {
|
||||
switch (request.method) {
|
||||
case "OPTIONS":
|
||||
return handleOPTIONS(request);
|
||||
case "GET":
|
||||
return handleGET(request);
|
||||
default:
|
||||
console.log(`Unsupported HTTP method ${request.method}`);
|
||||
return new Response(null, { status: 405 });
|
||||
}
|
||||
},
|
||||
} satisfies ExportedHandler;
|
||||
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
const headers = request.headers.get("Access-Control-Request-Headers");
|
||||
if (!areAllowedHeaders(headers))
|
||||
console.warn("Unknown header in list", headers);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
|
||||
"Access-Control-Allow-Headers": "*",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const isAllowedOrigin = (origin: string | null) => {
|
||||
if (!origin) return false;
|
||||
try {
|
||||
const url = new URL(origin);
|
||||
const hostname = url.hostname;
|
||||
return (
|
||||
origin == "ente://app" /* desktop app */ ||
|
||||
hostname.endsWith("ente.io") ||
|
||||
hostname.endsWith("ente.sh") ||
|
||||
hostname == "localhost"
|
||||
);
|
||||
} catch {
|
||||
// `origin` is likely an invalid URL.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const areAllowedHeaders = (headers: string | null) => {
|
||||
const allowed = ["x-auth-token", "x-client-package"];
|
||||
|
||||
if (!headers) return true;
|
||||
for (const header of headers.split(",")) {
|
||||
if (!allowed.includes(header.trim().toLowerCase())) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleGET = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
|
||||
// Random bots keep trying to pentest causing noise in the logs. If the
|
||||
// request doesn't have a fileID, we can just safely ignore it thereafter.
|
||||
const fileID = url.searchParams.get("fileID");
|
||||
if (!fileID) return new Response(null, { status: 400 });
|
||||
|
||||
let token = request.headers.get("X-Auth-Token");
|
||||
if (!token) {
|
||||
console.warn("Using deprecated token query param");
|
||||
token = url.searchParams.get("token");
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
console.error("No token provided");
|
||||
// return new Response(null, { status: 400 });
|
||||
}
|
||||
|
||||
// We forward the auth token as a query parameter to museum. This is so that
|
||||
// it does not get preserved when museum does a redirect to the presigned S3
|
||||
// URL that serves the actual thumbnail.
|
||||
//
|
||||
// See: [Note: Passing credentials for self-hosted file fetches]
|
||||
const params = new URLSearchParams();
|
||||
if (token) params.set("token", token);
|
||||
|
||||
let response = await fetch(
|
||||
`https://api.ente.io/files/download/${fileID}?${params.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
"User-Agent": request.headers.get("User-Agent") ?? "",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
response = new Response(response.body, response);
|
||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
return response;
|
||||
};
|
||||
1
infra/workers/files/tsconfig.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src"] }
|
||||
11
infra/workers/files/wrangler.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
name = "files"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-06-14"
|
||||
|
||||
routes = [
|
||||
{ pattern = "files.ente.io", custom_domain = true }
|
||||
]
|
||||
|
||||
tail_consumers = [
|
||||
{ service = "tail" }
|
||||
]
|
||||
@@ -2,8 +2,9 @@
|
||||
"name": "github-discord-notifier",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240314.0",
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Forward notifications from GitHub to Discord.
|
||||
*
|
||||
* This worker receives webhooks from GitHub, filters out the ones we don't
|
||||
* need, and forwards them to a Discord webhook.
|
||||
* need, and forwards the rest to a Discord webhook.
|
||||
*/
|
||||
export default {
|
||||
async fetch(request: Request, env: Env) {
|
||||
@@ -33,13 +33,13 @@ const handleRequest = async (request: Request, discordWebhookURL: string) => {
|
||||
// doesn't work for get silently ignored (Discord responds with a 204).
|
||||
// https://github.com/discord/discord-api-docs/issues/6203#issuecomment-1608151265
|
||||
|
||||
let response = await fetch(`${discordWebhookURL}/github`, {
|
||||
const response = await fetch(`${discordWebhookURL}/github`, {
|
||||
method: request.method,
|
||||
headers: request.headers,
|
||||
body: requestBody,
|
||||
});
|
||||
|
||||
if (response.status === 429) {
|
||||
if (response.status == 429) {
|
||||
// Sometimes Discord starts returning 429 Rate Limited responses when we
|
||||
// try to invoke the webhook.
|
||||
//
|
||||
@@ -79,7 +79,7 @@ const handleRequest = async (request: Request, discordWebhookURL: string) => {
|
||||
const action = requestJSON["action"];
|
||||
|
||||
if (activityURL && ["created", "opened"].includes(action)) {
|
||||
response = await fetch(discordWebhookURL, {
|
||||
return fetch(discordWebhookURL, {
|
||||
method: request.method,
|
||||
headers: request.headers,
|
||||
body: JSON.stringify({
|
||||
@@ -89,12 +89,5 @@ const handleRequest = async (request: Request, discordWebhookURL: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
const responseBody = await response.text();
|
||||
const newResponse = new Response(responseBody, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: response.headers,
|
||||
});
|
||||
|
||||
return newResponse;
|
||||
return response;
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src/**/*.ts"] }
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name = "github-discord-notifier"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-03-14"
|
||||
compatibility_date = "2024-06-14"
|
||||
|
||||
[vars]
|
||||
# Added as a secret via the Cloudflare dashboard
|
||||
|
||||
10
infra/workers/health-check/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "health-check",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
48
infra/workers/health-check/src/index.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/** Ping api.ente.io every minute and yell if it doesn't pong. */
|
||||
|
||||
export default {
|
||||
async scheduled(_, env: Env, ctx: ExecutionContext) {
|
||||
ctx.waitUntil(ping(env, ctx));
|
||||
},
|
||||
} satisfies ExportedHandler<Env>;
|
||||
|
||||
interface Env {
|
||||
NOTIFY_URL: string;
|
||||
CHAT_ID: string;
|
||||
}
|
||||
|
||||
const ping = async (env: Env, ctx: ExecutionContext) => {
|
||||
const notify = async (msg: string) =>
|
||||
sendMessage(`${msg} on ${Date()}`, env);
|
||||
|
||||
try {
|
||||
let timeout = setTimeout(() => {
|
||||
ctx.waitUntil(notify("Ping timed out"));
|
||||
}, 5000);
|
||||
const res = await fetch("https://api.ente.io/ping", {
|
||||
headers: {
|
||||
"User-Agent": "health-check",
|
||||
},
|
||||
});
|
||||
clearTimeout(timeout);
|
||||
if (!res.ok) await notify(`Ping failed (HTTP ${res.status})`);
|
||||
} catch (e) {
|
||||
await notify(`Ping failed (${e instanceof Error ? e.message : e})`);
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessage = async (message: string, env: Env) => {
|
||||
console.log(message);
|
||||
const res = await fetch(env.NOTIFY_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
chat_id: parseInt(env.CHAT_ID),
|
||||
parse_mode: "html",
|
||||
text: message,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error(`Failed to sendMessage (HTTP ${res.status})`);
|
||||
};
|
||||
1
infra/workers/health-check/tsconfig.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src"] }
|
||||
17
infra/workers/health-check/wrangler.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
name = "health-check"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-06-14"
|
||||
|
||||
# Disable the default route, this worker does not handle fetch.
|
||||
workers_dev = false
|
||||
|
||||
tail_consumers = [{ service = "tail" }]
|
||||
|
||||
[vars]
|
||||
# Added as a secret via the Cloudflare dashboard
|
||||
# NOTIFY_URL = ""
|
||||
# CHAT_ID = ""
|
||||
|
||||
[triggers]
|
||||
# Every minute
|
||||
crons = [ "*/1 * * * *" ]
|
||||
10
infra/workers/public-albums/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "public-albums",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
101
infra/workers/public-albums/src/index.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/** Proxy requests for files and thumbnails in public albums. */
|
||||
|
||||
export default {
|
||||
async fetch(request: Request) {
|
||||
switch (request.method) {
|
||||
case "OPTIONS":
|
||||
return handleOPTIONS(request);
|
||||
case "GET":
|
||||
return handleGET(request);
|
||||
default:
|
||||
console.log(`Unsupported HTTP method ${request.method}`);
|
||||
return new Response(null, { status: 405 });
|
||||
}
|
||||
},
|
||||
} satisfies ExportedHandler;
|
||||
|
||||
const handleOPTIONS = (request: Request) => {
|
||||
const origin = request.headers.get("Origin");
|
||||
if (!isAllowedOrigin(origin)) console.warn("Unknown origin", origin);
|
||||
const headers = request.headers.get("Access-Control-Request-Headers");
|
||||
if (!areAllowedHeaders(headers))
|
||||
console.warn("Unknown header in list", headers);
|
||||
return new Response("", {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Access-Token, X-Auth-Access-Token-JWT",
|
||||
// "Access-Control-Allow-Headers": "X-Auth-Access-Token, X-Auth-Access-Token-JWT, x-client-package",
|
||||
"Access-Control-Allow-Headers": "*",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const isAllowedOrigin = (origin: string | null) => {
|
||||
const allowed = ["albums.ente.io", "albums.ente.sh", "localhost"];
|
||||
|
||||
if (!origin) return false;
|
||||
try {
|
||||
const url = new URL(origin);
|
||||
return allowed.includes(url.hostname);
|
||||
} catch {
|
||||
// origin is likely an invalid URL
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const areAllowedHeaders = (headers: string | null) => {
|
||||
// TODO(MR): Stop sending "x-client-package"
|
||||
const allowed = [
|
||||
"x-auth-access-token",
|
||||
"x-auth-access-token-jwt",
|
||||
"x-client-package",
|
||||
];
|
||||
|
||||
if (!headers) return true;
|
||||
for (const header of headers.split(",")) {
|
||||
if (!allowed.includes(header.trim().toLowerCase())) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleGET = async (request: Request) => {
|
||||
const url = new URL(request.url);
|
||||
|
||||
const fileID = url.searchParams.get("fileID");
|
||||
if (!fileID) return new Response(null, { status: 400 });
|
||||
|
||||
let accessToken = request.headers.get("X-Auth-Access-Token");
|
||||
if (accessToken === undefined) {
|
||||
console.warn("Using deprecated accessToken query param");
|
||||
accessToken = url.searchParams.get("accessToken");
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
console.error("No accessToken provided");
|
||||
// return new Response(null, { status: 400 });
|
||||
}
|
||||
|
||||
let accessTokenJWT = request.headers.get("X-Auth-Access-Token-JWT");
|
||||
if (accessTokenJWT === undefined) {
|
||||
console.warn("Using deprecated accessTokenJWT query param");
|
||||
accessTokenJWT = url.searchParams.get("accessTokenJWT");
|
||||
}
|
||||
|
||||
const pathname = url.pathname;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (accessToken) params.set("accessToken", accessToken);
|
||||
if (accessTokenJWT) params.set("accessTokenJWT", accessTokenJWT);
|
||||
|
||||
let response = await fetch(
|
||||
`https://api.ente.io/public-collection/files${pathname}${fileID}?${params.toString()}`
|
||||
);
|
||||
|
||||
if (!response.ok) console.log("Upstream error", response.status);
|
||||
|
||||
response = new Response(response.body, response);
|
||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
return response;
|
||||
};
|
||||
1
infra/workers/public-albums/tsconfig.json
Normal file
@@ -0,0 +1 @@
|
||||
{ "extends": "../tsconfig.base.json", "include": ["src"] }
|
||||
11
infra/workers/public-albums/wrangler.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
name = "public-albums"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-06-14"
|
||||
|
||||
routes = [
|
||||
{ pattern = "public-albums.ente.io", custom_domain = true }
|
||||
]
|
||||
|
||||
tail_consumers = [
|
||||
{ service = "tail" }
|
||||
]
|
||||
10
infra/workers/tail/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "tail",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240614.0",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^3"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22"
|
||||
}
|
||||
72
infra/workers/tail/src/index.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* A tail worker that forwards all `console.log` (and siblings) to Loki.
|
||||
*
|
||||
* https://developers.cloudflare.com/workers/observability/logging/tail-workers/
|
||||
*/
|
||||
export default {
|
||||
async tail(events: TraceItem[], env: Env) {
|
||||
// If the tail worker itself throws an exception (it shouldn't, unless
|
||||
// Loki is down), we don't catch it so that it counts as an "error" in
|
||||
// the worker stats.
|
||||
await handleTail(events, env);
|
||||
},
|
||||
} satisfies ExportedHandler<Env>;
|
||||
|
||||
interface Env {
|
||||
/** The URL of the Loki instance to push logs to. */
|
||||
LOKI_PUSH_URL: string;
|
||||
/**
|
||||
* The value of the "Basic" authorization.
|
||||
*
|
||||
* [Note: HTTP basic authorization in worker fetch]
|
||||
*
|
||||
* Usually a Loki push URL is specified with the credentials inline, say
|
||||
* `http://user:pass@loki/path`. However, I cannot get that to work with the
|
||||
* `fetch` inside a Cloudflare worker. Instead, the credentials need to be
|
||||
* separately provided as the Authorization header of the form:
|
||||
*
|
||||
* Authorization: Basic ${btoa(user:pass)}
|
||||
*
|
||||
* The LOKI_AUTH secret is the "${btoa(user:pass)}" value.
|
||||
*/
|
||||
LOKI_AUTH: string;
|
||||
}
|
||||
|
||||
const handleTail = async (events: TraceItem[], env: Env) => {
|
||||
for (const event of events.filter(hasLogOrException))
|
||||
await pushLogLine(Date.now(), JSON.stringify(event), env);
|
||||
};
|
||||
|
||||
/** Return true if the {@link event} has at least one log or exception. */
|
||||
const hasLogOrException = (event: TraceItem) =>
|
||||
event.logs.length ?? event.exceptions.length;
|
||||
|
||||
/**
|
||||
* Send a log entry to (Grafana) Loki
|
||||
*
|
||||
* For more details about the protocol, see
|
||||
* https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs
|
||||
*
|
||||
* @param timestampMs Unix epoch (in milliseconds) when the event occurred.
|
||||
*
|
||||
* @param logLine The message to log.
|
||||
*
|
||||
* @param env The worker environment; we need it for the Loki URL and
|
||||
* credentials.
|
||||
*/
|
||||
const pushLogLine = async (timestampMs: number, logLine: string, env: Env) =>
|
||||
await fetch(env.LOKI_PUSH_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Basic ${env.LOKI_AUTH}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
streams: [
|
||||
{
|
||||
stream: { job: "worker" },
|
||||
values: [[`${timestampMs * 1e6}`, logLine]],
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||