Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b7b6e457b | ||
|
|
61c53e9d10 | ||
|
|
13fe460069 | ||
|
|
6b4e4b6822 | ||
|
|
8b9592c06e | ||
|
|
4a0301fe46 | ||
|
|
14820ad7a0 | ||
|
|
974c34a569 | ||
|
|
4dc31c3e60 | ||
|
|
fa60a22443 | ||
|
|
cf55c48b4c | ||
|
|
56290b1df6 | ||
|
|
8d468dbc91 | ||
|
|
1a654fe748 | ||
|
|
1606b74b40 | ||
|
|
8d82851741 | ||
|
|
a6ca5697d9 | ||
|
|
e01ba961a6 | ||
|
|
a256bc9922 |
@@ -1,36 +1,49 @@
|
||||
# Contributing
|
||||
|
||||
Thank you for showing interest in contributing to ente Authenticator. There are a couple of ways to help
|
||||
out. This document contains some general guidelines for each type of
|
||||
contribution.
|
||||
Thank you for showing interest in contributing to ente Authenticator. There are
|
||||
a couple of ways to help out. This document contains some general guidelines for
|
||||
each type of contribution.
|
||||
|
||||
|
||||
## Translations
|
||||
[](https://crowdin.com/project/ente-authenticator-app)
|
||||
|
||||
We use [Crowdin](https://crowdin.com/project/ente-authenticator-app) to crowdsource
|
||||
translations of ente Authenticator.
|
||||
If your language is not listed for translation, feel free to [create a GitHub issue](https://github.com/ente-io/auth/issues/new?title=Request+for+New+Language+Translation&body=Language+name%3A) to have it added.
|
||||
We use [Crowdin](https://crowdin.com/project/ente-authenticator-app) to
|
||||
crowdsource translations of ente Authenticator. If your language is not listed
|
||||
for translation, feel free to [create a GitHub
|
||||
issue](https://github.com/ente-io/auth/issues/new?title=Request+for+New+Language+Translation&body=Language+name%3A)
|
||||
to have it added.
|
||||
|
||||
## Icons
|
||||
|
||||
ente Auth supports the icon pack provided by
|
||||
[simple-icons](https://github.com/simple-icons/simple-icons).
|
||||
|
||||
If you would like to add your own custom icon, please open a pull-request
|
||||
with the relevant SVG and color
|
||||
code ([example PR](https://github.com/ente-io/auth/pull/213/files)).
|
||||
If you would like to add your own custom icon, please open a pull-request with
|
||||
the relevant SVG placed within `assets/custom-icons/icons` and add the
|
||||
corresponding entry within `assets/custom-icons/_data/custom-icons.json`.
|
||||
|
||||
This JSON file contains the following attributes:
|
||||
|
||||
| Attribute | Usecase | Required |
|
||||
|---|---|---|
|
||||
| `title` | Name of the service. | Yes |
|
||||
| `slug` | If the icon's SVG file has a name different from the `title` | No |
|
||||
| `hex` | Color code for the icon | No |
|
||||
| `altNames` | If the same service goes by different names or has different instances (eg. Mastodon) | No |
|
||||
|
||||
Here is an [example PR](https://github.com/ente-io/auth/pull/213/files).
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
If you're planning on adding a new feature or making other changes, please
|
||||
discuss it with us by creating [an
|
||||
issue](https://github.com/ente-io/auth/issues/new)
|
||||
on GitHub. Discussing your idea with us first ensures that everyone is on the
|
||||
same page before you start working on your change.
|
||||
issue](https://github.com/ente-io/auth/issues/new) on GitHub. Discussing your
|
||||
idea with us first ensures that everyone is on the same page before you start
|
||||
working on your change.
|
||||
|
||||
### 💻 Setup
|
||||
### Setup
|
||||
|
||||
1. [Install Flutter v3.10.6](https://flutter.dev/docs/get-started/install)
|
||||
2. Clone this repository with `git clone git@github.com:ente-io/auth.git`
|
||||
@@ -43,9 +56,12 @@ same page before you start working on your change.
|
||||
|
||||
|
||||
#### Localization
|
||||
If the feature requires adding new strings, you can do that by following these steps:
|
||||
If the feature requires adding new strings, you can do that by following these
|
||||
steps:
|
||||
|
||||
1. Add a new entry inside [app_en.arb](https://github.com/ente-io/auth/blob/main/lib/l10n/arb/app_en.arb) (Remember to save)
|
||||
1. Add a new entry inside
|
||||
[app_en.arb](https://github.com/ente-io/auth/blob/main/lib/l10n/arb/app_en.arb)
|
||||
(Remember to save)
|
||||
2. In your dart file, add follwing import
|
||||
```dart
|
||||
import "package:ente_auth/l10n/l10n.dart";
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
"title": "Addy.io",
|
||||
"slug": "addy_io"
|
||||
},
|
||||
{
|
||||
"title": "Airtable"
|
||||
},
|
||||
{
|
||||
"title": "Anycoin Direct",
|
||||
"slug": "anycoindirect"
|
||||
@@ -27,6 +30,10 @@
|
||||
{
|
||||
"title": "Bitwarden"
|
||||
},
|
||||
{
|
||||
"title": "Brave Creators",
|
||||
"slug": "brave_creators"
|
||||
},
|
||||
{
|
||||
"title": "Bybit"
|
||||
},
|
||||
@@ -43,10 +50,22 @@
|
||||
"slug": "controld",
|
||||
"hex": "5FD800"
|
||||
},
|
||||
{
|
||||
"title": "Discourse"
|
||||
},
|
||||
{
|
||||
"title": "dus.net",
|
||||
"slug": "dusnet"
|
||||
},
|
||||
{
|
||||
"title": "ente",
|
||||
"hex": "1DB954"
|
||||
},
|
||||
{
|
||||
"title": "Epic Games",
|
||||
"slug": "epic_games",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "Filen",
|
||||
"hex": "858585"
|
||||
@@ -59,12 +78,19 @@
|
||||
"title": "GitHub",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "GitLab",
|
||||
"slug": "gitlab"
|
||||
},
|
||||
{
|
||||
"title": "Google"
|
||||
},
|
||||
{
|
||||
"title": "ING"
|
||||
},
|
||||
{
|
||||
"title": "INWX"
|
||||
},
|
||||
{
|
||||
"title": "Instagram"
|
||||
},
|
||||
@@ -91,9 +117,9 @@
|
||||
"title": "KuCoin",
|
||||
"hex": "01BC8D"
|
||||
},
|
||||
{
|
||||
{
|
||||
"title": "La Poste",
|
||||
"slug": "laposte"
|
||||
"slug": "laposte"
|
||||
},
|
||||
{
|
||||
"title": "Mastodon",
|
||||
@@ -107,6 +133,9 @@
|
||||
{
|
||||
"title": "Mozilla"
|
||||
},
|
||||
{
|
||||
"title": "NextDNS"
|
||||
},
|
||||
{
|
||||
"title": "ngrok",
|
||||
"hex": "858585"
|
||||
@@ -170,9 +199,24 @@
|
||||
"title": "Revolt",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "Rust Language Forum",
|
||||
"slug": "rust_language_forum",
|
||||
"hex": "000000"
|
||||
},
|
||||
{
|
||||
"title": "service-bw"
|
||||
},
|
||||
{
|
||||
"title": "SimpleLogin"
|
||||
},
|
||||
{
|
||||
"title": "Sipgate"
|
||||
},
|
||||
{
|
||||
"title": "Skiff",
|
||||
"hex": "EF5A3C"
|
||||
},
|
||||
{
|
||||
"title": "Snapchat"
|
||||
},
|
||||
@@ -181,6 +225,11 @@
|
||||
"slug": "standardnotes",
|
||||
"hex": "2173E6"
|
||||
},
|
||||
{
|
||||
"title": "TCPShield",
|
||||
"slug": "tcpshield",
|
||||
"hex": "FFFFFF"
|
||||
},
|
||||
{
|
||||
"title": "Techlore"
|
||||
},
|
||||
@@ -217,6 +266,11 @@
|
||||
"title": "Unity",
|
||||
"hex": "858585"
|
||||
},
|
||||
{
|
||||
"title": "Uphold",
|
||||
"slug": "uphold",
|
||||
"hex": "6FE68A"
|
||||
},
|
||||
{
|
||||
"title": "WHMCS"
|
||||
},
|
||||
@@ -231,13 +285,6 @@
|
||||
"title": "X",
|
||||
"altNames": ["twitter"],
|
||||
"slug": "x"
|
||||
},
|
||||
{
|
||||
"title": "NextDNS"
|
||||
},
|
||||
{
|
||||
"title": "Skiff",
|
||||
"hex": "EF5A3C"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
1
assets/custom-icons/icons/airtable.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Airtable</title><path fill="#ffba05" d="M11.992 1.966c-.434 0-.87.086-1.28.257L1.779 5.917c-.503.208-.49.908.012 1.116l8.982 3.558a3.266 3.266 0 0 0 2.454 0l8.982-3.558c.503-.196.503-.908.012-1.116l-8.957-3.694a3.255 3.255 0 0 0-1.272-.257z"/><path fill="#39caff" d="M23.4 8.056a.589.589 0 0 0-.222.045l-10.012 3.877a.612.612 0 0 0-.38.564v8.896a.6.6 0 0 0 .821.552L23.62 18.1a.583.583 0 0 0 .38-.551V8.653a.6.6 0 0 0-.6-.596z"/><path fill="#dc043b" d="M.676 8.095a.644.644 0 0 0-.48.19C.086 8.396 0 8.53 0 8.69v8.355c0 .442.515.737.908.54l6.27-3.006.307-.147 2.969-1.436c.466-.22.43-.908-.061-1.092L.883 8.138a.57.57 0 0 0-.207-.044z"/><path fill-opacity="0.25" d="M10.451,12.997l-2.972,1.434l-7.287,-6.144c0.046,-0.046 0.098,-0.084 0.152,-0.114c0.15,-0.09 0.363,-0.114 0.545,-0.042l9.512,3.769c0.483,0.191 0.521,0.869 0.05,1.097"/></svg>
|
||||
|
After Width: | Height: | Size: 918 B |
114
assets/custom-icons/icons/brave_creators.svg
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg6"
|
||||
sodipodi:docname="brave.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="48"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
</defs>
|
||||
<g
|
||||
transform="translate(48.065,48.066)"
|
||||
id="r-F4iK9D9hoWKR6dRPdW9">
|
||||
<g
|
||||
id="g6">
|
||||
<g
|
||||
transform="translate(-0.065,-0.066)"
|
||||
id="Ii0aKVyTWvdbjVfK_ZaN0">
|
||||
<linearGradient
|
||||
id="SVGID_0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0.671"
|
||||
y1="64.319"
|
||||
x2="55.200001"
|
||||
y2="64.319">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:rgb(255,85,0);stop-opacity: 1"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="41%"
|
||||
style="stop-color:rgb(255,85,0);stop-opacity: 1"
|
||||
id="stop2" />
|
||||
<stop
|
||||
offset="58.199999999999996%"
|
||||
style="stop-color:rgb(255,32,0);stop-opacity: 1"
|
||||
id="stop3" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:rgb(255,32,0);stop-opacity: 1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="opacity:1;fill:url(#SVGID_0);fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-27.935,-31.934)"
|
||||
d="m 53.292,15.321 1.5,-3.676 c 0,0 -1.909,-2.043 -4.227,-4.358 C 48.248,4.972 43.34,6.334 43.34,6.334 L 37.751,0 H 18.12 l -5.589,6.334 c 0,0 -4.908,-1.362 -7.225,0.953 C 2.988,9.602 1.08,11.645 1.08,11.645 l 1.5,3.676 -1.91,5.447 c 0,0 5.614,21.236 6.272,23.83 1.295,5.106 2.181,7.08 5.862,9.668 3.68,2.587 10.36,7.08 11.45,7.762 1.091,0.68 2.455,1.84 3.682,1.84 1.227,0 2.59,-1.16 3.68,-1.84 1.091,-0.681 7.77,-5.175 11.452,-7.762 3.68,-2.587 4.567,-4.562 5.862,-9.668 0.657,-2.594 6.27,-23.83 6.27,-23.83 z"
|
||||
stroke-linecap="round"
|
||||
id="path4" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.064,-1.7095)"
|
||||
id="yFALuw9WCf5yfG8AbQIoW">
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-27.936,-30.2905)"
|
||||
d="m 34.888,11.508 c 0.818,0 6.885,-1.157 6.885,-1.157 0,0 7.189,8.68 7.189,10.536 0,1.534 -0.619,2.134 -1.347,2.842 -0.152,0.148 -0.31,0.3 -0.467,0.468 l -5.39,5.717 c -0.05786,0.06078 -0.116534,0.120787 -0.176,0.18 -0.538,0.54 -1.33,1.336 -0.772,2.658 l 0.115,0.269 c 0.613,1.432 1.37,3.2 0.407,4.99 -1.025,1.906 -2.78,3.178 -3.905,2.967 -1.124,-0.21 -3.766,-1.589 -4.737,-2.218 -0.971,-0.63 -4.05,-3.166 -4.05,-4.137 0,-0.809 2.214,-2.155 3.29,-2.81 0.214,-0.13 0.383,-0.232 0.48,-0.298 0.111,-0.075 0.297,-0.19 0.526,-0.332 0.981,-0.61 2.754,-1.71 2.799,-2.197 0.055,-0.602 0.034,-0.778 -0.758,-2.264 -0.168,-0.316 -0.365,-0.654 -0.568,-1.004 -0.754,-1.295 -1.598,-2.745 -1.41,-3.784 0.21,-1.173 2.05,-1.845 3.608,-2.415 0.194,-0.07 0.385,-0.14 0.567,-0.209 l 1.623,-0.609 c 1.556,-0.582 3.284,-1.229 3.57,-1.36 0.394,-0.181 0.292,-0.355 -0.903,-0.468 -0.193439,-0.01897 -0.386775,-0.03897 -0.58,-0.06 -1.48,-0.157 -4.209,-0.446 -5.535,-0.077 -0.261,0.073 -0.553,0.152 -0.86,0.235 -1.49,0.403 -3.317,0.897 -3.493,1.182 -0.03,0.05 -0.06,0.093 -0.089,0.133 -0.168,0.238 -0.277,0.394 -0.091,1.406 0.055,0.302 0.169,0.895 0.31,1.629 0.41,2.148 1.053,5.498 1.134,6.25 0.011,0.106 0.024,0.207 0.036,0.305 0.103,0.84 0.171,1.399 -0.805,1.622 l -0.255,0.058 c -1.102,0.252 -2.717,0.623 -3.3,0.623 -0.584,0 -2.2,-0.37 -3.302,-0.623 L 24.38,29.498 c -0.976,-0.223 -0.907,-0.782 -0.804,-1.622 0.012,-0.098 0.024,-0.2 0.035,-0.305 0.081,-0.753 0.725,-4.112 1.137,-6.259 0.14,-0.73 0.253,-1.32 0.308,-1.62 0.185,-1.012 0.076,-1.168 -0.092,-1.406 -0.03095,-0.04368 -0.06095,-0.08803 -0.09,-0.133 -0.174,-0.285 -2,-0.779 -3.491,-1.182 -0.307,-0.083 -0.6,-0.162 -0.86,-0.235 -1.327,-0.37 -4.055,-0.08 -5.535,0.077 -0.226,0.024 -0.422,0.045 -0.58,0.06 -1.196,0.113 -1.297,0.287 -0.903,0.468 0.285,0.131 2.013,0.778 3.568,1.36 0.597,0.223 1.17,0.437 1.624,0.609 0.183,0.069 0.373,0.138 0.568,0.21 1.558,0.57 3.398,1.241 3.608,2.414 0.187,1.039 -0.657,2.489 -1.41,3.784 -0.204,0.35 -0.4,0.688 -0.569,1.004 -0.791,1.486 -0.812,1.662 -0.757,2.264 0.044,0.488 1.816,1.587 2.798,2.197 0.229,0.142 0.415,0.257 0.526,0.332 0.098,0.066 0.266,0.168 0.48,0.298 1.076,0.654 3.29,2 3.29,2.81 0,0.97 -3.078,3.507 -4.05,4.137 -0.97,0.63 -3.612,2.008 -4.737,2.218 -1.124,0.21 -2.88,-1.061 -3.904,-2.966 -0.963,-1.791 -0.207,-3.559 0.406,-4.99 l 0.115,-0.27 C 15.62,31.43 14.828,30.634 14.289,30.094 14.22987,30.03478 14.171528,29.974778 14.114,29.914 L 8.724,24.197 C 8.566,24.03 8.408,23.877 8.256,23.729 7.528,23.022 6.91,22.421 6.91,20.887 c 0,-1.855 7.189,-10.536 7.189,-10.536 0,0 6.066,1.157 6.884,1.157 0.653,0 1.913,-0.433 3.227,-0.885 0.333,-0.114 0.669,-0.23 1,-0.34 1.635,-0.545 2.726,-0.549 2.726,-0.549 0,0 1.09,0.004 2.726,0.549 0.33,0.11 0.667,0.226 1,0.34 1.313,0.452 2.574,0.885 3.226,0.885 z m -1.041,30.706 c 1.282,0.66 2.192,1.128 2.536,1.343 0.445,0.278 0.174,0.803 -0.232,1.09 -0.405,0.285 -5.853,4.499 -6.381,4.965 l -0.215,0.191 c -0.509,0.459 -1.159,1.044 -1.62,1.044 -0.46,0 -1.11,-0.586 -1.62,-1.044 l -0.213,-0.191 c -0.53,-0.466 -5.977,-4.68 -6.382,-4.966 -0.405,-0.286 -0.677,-0.81 -0.232,-1.09 0.344,-0.214 1.255,-0.683 2.539,-1.344 l 1.22,-0.629 c 1.92,-0.992 4.315,-1.837 4.689,-1.837 0.373,0 2.767,0.844 4.689,1.837 0.436,0.226 0.845,0.437 1.222,0.63 z"
|
||||
stroke-linecap="round"
|
||||
id="path5" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.0645,-26.246)"
|
||||
id="0KuDkb-_5PZSfGEzYnH-2">
|
||||
<linearGradient
|
||||
id="SVGID_1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="6.2779999"
|
||||
y1="11.466"
|
||||
x2="50.564999"
|
||||
y2="11.466">
|
||||
<stop
|
||||
offset="0%"
|
||||
style="stop-color:rgb(255,69,42);stop-opacity: 1"
|
||||
id="stop5" />
|
||||
<stop
|
||||
offset="100%"
|
||||
style="stop-color:rgb(255,32,0);stop-opacity: 1"
|
||||
id="stop6" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="opacity:1;fill:url(#SVGID_1);fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-27.9355,-5.754)"
|
||||
d="M 43.34,6.334 37.751,0 H 18.12 l -5.589,6.334 c 0,0 -4.908,-1.362 -7.225,0.953 0,0 6.544,-0.59 8.793,3.064 0,0 6.066,1.157 6.884,1.157 0.818,0 2.59,-0.68 4.226,-1.225 1.636,-0.545 2.727,-0.549 2.727,-0.549 0,0 1.09,0.004 2.726,0.549 1.636,0.545 3.408,1.225 4.226,1.225 0.818,0 6.885,-1.157 6.885,-1.157 C 44.022,6.697 50.565,7.287 50.565,7.287 48.248,4.972 43.34,6.334 43.34,6.334 Z"
|
||||
stroke-linecap="round"
|
||||
id="path6" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.1 KiB |
1
assets/custom-icons/icons/discourse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Discourse</title><path d="M11.992 0C5.482 0 0 5.278 0 11.791V24l11.99-.012c6.51 0 11.79-5.481 11.79-11.991C23.78 5.486 18.495 0 11.992 0"/><path d="M12.108 4.564c-4.009.002-7.306 3.301-7.306 7.31 0 1.215.302 2.411.881 3.479L4.36 19.607l4.749-1.072a7.312 7.312 0 0 0 3.002.645c4.009 0 7.308-3.299 7.308-7.308 0-4.008-3.297-7.306-7.305-7.308z" fill="#fff9ae"/><path d="M17.822 16.395a7.307 7.307 0 0 1-8.713 2.128L4.36 19.61l4.834-.571a7.306 7.306 0 0 0 8.712-11.613 7.306 7.306 0 0 1-.084 8.969" fill="#00aeef"/><path d="M17.413 15.006a7.307 7.307 0 0 1-8.443 3.027L4.36 19.61l4.749-1.075A7.306 7.306 0 0 0 16.56 6.078a7.305 7.305 0 0 1 .853 8.928" fill="#00a94f"/><path d="M6.12 15.515a7.308 7.308 0 0 1 11.79-8.091 7.308 7.308 0 0 0-12.227 7.929L4.36 19.607z" fill="#f15d22"/><path d="M5.683 15.353A7.308 7.308 0 0 1 16.56 6.078 7.308 7.308 0 0 0 5.232 15.24l-.869 4.37z" fill="#d0232b"/></svg>
|
||||
|
After Width: | Height: | Size: 973 B |
1
assets/custom-icons/icons/dusnet.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>dus.net</title><circle cx="12" cy="21.799" r="2.201"/><path d="M5.467 0a2.202 2.202 0 1 0 .001 4.403A2.202 2.202 0 0 0 5.467 0M12 0a2.201 2.201 0 1 0 0 4.402A2.201 2.201 0 0 0 12 0m6.533 4.402a2.201 2.201 0 1 0 0-4.402 2.201 2.201 0 0 0 0 4.402M5.467 6.533a2.201 2.201 0 1 0 0 4.402 2.201 2.201 0 0 0 0-4.402m6.533 0a2.2 2.2 0 1 0-.001 4.4 2.2 2.2 0 0 0 .001-4.4m6.533 0a2.201 2.201 0 1 0-.001 4.403 2.201 2.201 0 0 0 .001-4.403M5.467 13.065a2.202 2.202 0 1 0 .001 4.403 2.202 2.202 0 0 0-.001-4.403m6.533 0a2.201 2.201 0 1 0 0 4.402 2.201 2.201 0 0 0 0-4.402m6.533 0a2.202 2.202 0 1 0 0 4.404 2.202 2.202 0 0 0 0-4.404" fill="#eb311b"/></svg>
|
||||
|
After Width: | Height: | Size: 721 B |
10
assets/custom-icons/icons/epic_games.svg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
84
assets/custom-icons/icons/gitlab.svg
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg4"
|
||||
sodipodi:docname="gitlab.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview4"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="48"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(2,0,0,2,47.999807,47.999999)"
|
||||
id="LlMVISacmLRypCAN8RaOa">
|
||||
<g
|
||||
id="g4">
|
||||
<g
|
||||
transform="translate(-0.00126224)"
|
||||
id="jXZGVBwYEboir0aGofEdX">
|
||||
<path
|
||||
style="opacity:1;fill:#e24329;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-15.998738,-15.999998)"
|
||||
d="M 31.4618,12.7787 31.417,12.6641 27.0667,1.31308 C 26.9783,1.09046 26.8218,0.90145 26.6197,0.773028 26.416,0.644476 26.1775,0.582308 25.937,0.595107 25.6965,0.607906 25.4659,0.695039 25.277,0.844481 25.0899,0.994513 24.955,1.1998 24.8915,1.43106 L 21.9503,10.4324 H 10.0509 L 7.10976,1.43106 C 7.04625,1.1998 6.91133,0.994513 6.72425,0.844481 6.53618,0.694035 6.30572,0.606246 6.06523,0.593431 5.82473,0.580616 5.58625,0.64342 5.38326,0.773028 5.18023,0.900924 5.02312,1.09005 4.9346,1.31308 L 0.579314,12.679 0.534448,12.792 c -0.6252016,1.637 -0.702052,3.4327 -0.218996,5.1171 0.483056,1.6844 1.499908,3.1665 2.897638,4.2233 l 0.01662,0.0116 0.03822,0.0299 6.63513,4.9668 3.28014,2.4843 1.9941,1.5104 c 0.2342,0.177 0.5198,0.2728 0.8134,0.2728 0.2935,0 0.5791,-0.0958 0.8134,-0.2728 l 1.994,-1.5104 3.2818,-2.4843 6.6734,-4.9967 0.0182,-0.0133 c 1.4025,-1.0558 2.4234,-2.5391 2.9087,-4.2262 0.4854,-1.687 0.4087,-3.4861 -0.2184,-5.1258 z"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(8.0042462,3.9024)"
|
||||
id="_HnOE30YI3q64iu3Kyf5i">
|
||||
<path
|
||||
style="opacity:1;fill:#fc6d26;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-24.004246,-19.9024)"
|
||||
d="m 31.462,12.7787 -0.0448,-0.1146 c -2.1217,0.4372 -4.121,1.3364 -5.8558,2.6337 l -9.5531,7.24 c 3.2569,2.4627 6.0918,4.6029 6.0918,4.6029 l 6.6733,-4.9967 0.0183,-0.0133 c 1.399,-1.0584 2.4159,-2.543 2.8976,-4.2298 0.4817,-1.6869 0.4019,-3.4846 -0.2273,-5.1222 z"
|
||||
stroke-linecap="round"
|
||||
id="path2" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.00585,10.973)"
|
||||
id="AuQqbk918YYSmtG3qADkx">
|
||||
<path
|
||||
style="opacity:1;fill:#fca326;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-15.99415,-26.973)"
|
||||
d="m 9.9082,27.1407 3.2752,2.4843 1.994,1.5104 c 0.2343,0.177 0.5198,0.2728 0.8134,0.2728 0.2936,0 0.5792,-0.0958 0.8134,-0.2728 l 1.994,-1.5104 3.2819,-2.4843 c 0,0 -2.8349,-2.1402 -6.0918,-4.6029 z"
|
||||
stroke-linecap="round"
|
||||
id="path3" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-7.9959499,3.90655)"
|
||||
id="WbT8aWwyHoQxpOUXtkBeV">
|
||||
<path
|
||||
style="opacity:1;fill:#fc6d26;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-8.0040501,-19.90655)"
|
||||
d="M 6.43513,15.3045 C 4.70076,14.0067 2.70123,13.108 0.579333,12.6724 l -0.044866,0.113 c -0.6268073,1.6378 -0.704503,3.4349 -0.221388,5.1207 0.483115,1.6858 1.500881,3.169 2.900031,4.2263 l 0.01662,0.0116 0.03822,0.0299 6.63512,4.9668 6.10503,-4.6029 z"
|
||||
stroke-linecap="round"
|
||||
id="path4" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
1
assets/custom-icons/icons/inwx.svg
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
64
assets/custom-icons/icons/rust_language_forum.svg
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
sodipodi:docname="rust.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview2"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="47.876448"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<defs
|
||||
id="defs1">
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(0.61244177,0,0,0.61244177,48.58182,48.643064)"
|
||||
id="d0KfchOoJLd1am88Nf2bl">
|
||||
<g
|
||||
id="g2">
|
||||
<g
|
||||
transform="translate(-0.95,-1.05)"
|
||||
id="CssRuECJ6utZ-6lKixFij">
|
||||
<path
|
||||
style="opacity:1;fill:#000000;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-71.05,-70.95)"
|
||||
d="M 71.05,23.68 C 44.99,23.68 23.78,44.9 23.78,70.95 23.78,97 45,118.22 71.05,118.22 97.1,118.22 118.32,97 118.32,70.95 118.32,44.9 97.1,23.68 71.05,23.68 Z m -0.07,4.2 c 1.680761,0.04353 3.02056,1.423255 3.02,3.11 0,1.717606 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.392394 -3.11,-3.11 -3.52e-4,-0.840656 0.339633,-1.645648 0.942484,-2.231544 C 69.325335,28.172561 70.139696,27.855672 70.98,27.88 Z M 78.1,33 c 11.050222,2.069744 20.631432,8.893613 26.2,18.66 l -3.67,8.28 c -0.63,1.43 0.02,3.11 1.44,3.75 l 7.06,3.13 c 0.219,2.206835 0.24577,4.428529 0.08,6.64 h -3.93 c -0.39,0 -0.55,0.26 -0.55,0.64 v 1.8 c 0,4.24 -2.39,5.17 -4.49,5.4 -2,0.23 -4.21,-0.84 -4.49,-2.06 -1.18,-6.63 -3.14,-8.04 -6.24,-10.49 3.85,-2.44 7.85,-6.05 7.85,-10.87 0,-5.21 -3.57,-8.49 -6,-10.1 -3.42,-2.25 -7.2,-2.7 -8.22,-2.7 H 42.54 C 48.154011,38.808406 55.67907,34.5626 63.95,33 l 4.79,5.02 c 1.08,1.13 2.87,1.18 4,0.09 z M 33.9,56.02 c 1.682359,0.04871 3.020705,1.426936 3.02,3.11 0,1.717606 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.392394 -3.11,-3.11 -3.52e-4,-0.840656 0.339633,-1.645648 0.942484,-2.231544 C 32.245335,56.312561 33.059696,55.995672 33.9,56.02 Z m 74.15,0.14 c 1.68236,0.04871 3.0207,1.426936 3.02,3.11 0,1.717606 -1.39239,3.11 -3.11,3.11 -1.71761,0 -3.11,-1.392394 -3.11,-3.11 -3.5e-4,-0.840656 0.33963,-1.645648 0.94248,-2.231544 0.60285,-0.585895 1.41722,-0.902784 2.25752,-0.878456 z m -68.29,0.5 h 5.42 V 81.1 H 34.24 C 32.88888,76.35544 32.46782,71.394402 33,66.49 l 6.7,-2.98 c 1.43,-0.64 2.08,-2.31 1.44,-3.74 z m 22.62,0.26 h 12.91 c 0.67,0 4.71,0.77 4.71,3.8 0,2.51 -3.1,3.41 -5.65,3.41 H 62.37 Z m 0,17.56 h 9.89 c 0.9,0 4.83,0.26 6.08,5.28 0.39,1.54 1.26,6.56 1.85,8.17 0.59,1.8 2.98,5.4 5.53,5.4 h 16.14 c -1.08168,1.448565 -2.26464,2.818663 -3.54,4.1 l -6.57,-1.41 c -1.53,-0.33 -3.04,0.65 -3.37,2.18 l -1.56,7.28 c -10.151161,4.59844 -21.802519,4.54367 -31.91,-0.15 L 53.36,98.05 C 53.03,96.52 51.53,95.54 50,95.87 l -6.43,1.38 c -1.193214,-1.230834 -2.302379,-2.54045 -3.32,-3.92 h 31.27 c 0.35,0 0.59,-0.06 0.59,-0.39 V 81.88 c 0,-0.32 -0.24,-0.39 -0.59,-0.39 H 62.37 Z M 47.95,99.81 c 1.682359,0.04871 3.020705,1.42694 3.02,3.11 0,1.71761 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.39239 -3.11,-3.11 -3.52e-4,-0.84066 0.339633,-1.64565 0.942484,-2.23154 C 46.295335,100.10256 47.109696,99.785672 47.95,99.81 Z M 94,99.95 c 1.682359,0.04871 3.020705,1.42694 3.02,3.11 0,1.71761 -1.392394,3.11 -3.11,3.11 -1.717606,0 -3.11,-1.39239 -3.11,-3.11 -3.52e-4,-0.84066 0.339633,-1.64565 0.942484,-2.23154 C 92.345335,100.24256 93.159696,99.925672 94,99.95 Z"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.95,-1.05)"
|
||||
id="Sz8Hb_caEIP6YkrZ7l00L">
|
||||
<path
|
||||
style="opacity:1;fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
transform="translate(-71.05,-70.95)"
|
||||
d="m 115.68,70.95 c 0,11.836612 -4.70208,23.188427 -13.07182,31.55818 C 94.238427,110.87792 82.886612,115.58 71.05,115.58 c -24.648468,0 -44.63,-19.981532 -44.63,-44.63 0,-24.648468 19.981532,-44.63 44.63,-44.63 24.648468,0 44.63,19.981532 44.63,44.63 z m -0.84,-4.31 6.96,4.31 -6.96,4.31 5.98,5.59 -7.66,2.87 4.78,6.65 -8.09,1.32 3.4,7.46 -8.19,-0.29 1.88,7.98 -7.98,-1.88 0.29,8.19 -7.46,-3.4 -1.32,8.09 -6.65,-4.78 -2.87,7.66 -5.59,-5.98 -4.31,6.96 -4.31,-6.96 -5.59,5.98 -2.87,-7.66 -6.65,4.78 -1.32,-8.09 -7.46,3.4 0.29,-8.19 -7.98,1.88 1.88,-7.98 -8.19,0.29 3.4,-7.46 -8.09,-1.32 4.78,-6.65 -7.66,-2.87 5.98,-5.59 -6.96,-4.31 6.96,-4.31 -5.98,-5.59 7.66,-2.87 -4.78,-6.65 8.09,-1.32 -3.4,-7.46 8.19,0.29 -1.88,-7.98 7.98,1.88 -0.29,-8.19 7.46,3.4 1.32,-8.09 6.65,4.78 2.87,-7.66 5.59,5.98 4.31,-6.96 4.31,6.96 5.59,-5.98 2.87,7.66 6.65,-4.78 1.32,8.09 7.46,-3.4 -0.29,8.19 7.98,-1.88 -1.88,7.98 8.19,-0.29 -3.4,7.46 8.09,1.32 -4.78,6.65 7.66,2.87 z"
|
||||
stroke-linecap="round"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
1
assets/custom-icons/icons/service-bw.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg rols="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>service-bw</title><path fill="#f8dd15" d="M7.926 7.962c-.582.086-.083.499-.083.499l.618-.477s.035-.09-.535-.022 M9.571 10.864c.144-1.248-1.379-2.88-1.379-2.88l.592-.794-1.478.407s-1.581-.691-3.946.793a1.717 1.717 0 0 0 0 .989c.097.322.925-.48 1.107.154-.269.078-.548.12-.829.125a1.239 1.239 0 0 1-.758-.196 2.065 2.065 0 0 1-.48-.96c-.073-.356-.342 1.447 1.21 1.447.293.026.588-.004.87-.09-.051.858-.829.215-.829.215v.988s1.258-.163 1.488-.339c-.064.221-.173.819-.173.819l-2.025-.08S.691 9.478 0 11.856l1.581.099 3.651 2.378-1.677 1.28s-2.56-.858-2.464 1.123l3.251.058 5.095-1.184v-.586s1.449-.099 1.747-.099a15.308 15.308 0 0 0 1.862-.778v-3.232c-1.724.202-3.193.269-3.475-.051m-3.859-2.88-.618.493s-.499-.416.084-.499c.582-.084.534.022.534.022z M11.546 8.883c-.298-.601.492-1.683.492-1.683s-2.169.595-1.776 1.981c.304 1.069 2.01.96 2.778.854v-.96c-.618.103-1.334.135-1.494-.192"/><path d="M13.28 14.024v4.056h-.32V5.92h.32v3.146c.247-.045.493-.099.736-.164 0 0 5.203-1.52 5.622-1.6.42-.08 2.269-.396 2.762 1.485.176 1.415-.48 1.776-.995 2.279.883.08 1.184 2.393 1.184 3.068 1.062-.371 1.283.298 1.382.298.099 0-.089 2.179-.089 2.179l-2.762-.096s-.352-1.017 1.28-1.081c-2.275-.692-3.261-2.068-3.261-2.068s-.889 1.104-1.184 1.6c-.294.496-.393 1.642-.393 1.642H14.01c.06-.55.182-.858.588-1.046l1.476.041.387-2.771-.413-.099s-1.449.677-2.768 1.291m0-3.995v.845c2.485-.308 5.388-.857 5.958-.912a1.866 1.866 0 0 1 1.479.396s.598.496.79-.988c.192-1.485-1.974-1.204-2.368-1.088-.393.115-5.705 1.718-5.705 1.718s-.057.012-.154.029"/></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
1
assets/custom-icons/icons/sipgate.svg
Normal file
|
After Width: | Height: | Size: 14 KiB |
27
assets/custom-icons/icons/tcpshield.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 686 802" width="686" height="802">
|
||||
<title>TCPShield</title>
|
||||
<style>
|
||||
.s0 { fill: #ffffff;stroke: #414042;stroke-miterlimit:10 }
|
||||
.s1 { fill: #ffffff }
|
||||
</style>
|
||||
<g id="Layer 1">
|
||||
<g id="Layer 2 1 ">
|
||||
</g>
|
||||
<g id="Layer 1 1 ">
|
||||
<g id="<Group>">
|
||||
<path id="<Path>" class="s0" d="m205.2 141.5c6.8-6.1 13.6-12 20.5-17.8 7.5-6.1 15-12.2 22.6-17.9 3.8-2.9 7.7-5.7 11.5-8.5 1.9-1.4 3.9-2.7 5.8-4.1 1.9-1.3 3.9-2.7 5.8-4 2-1.3 3.9-2.6 5.9-3.9 2-1.3 3.9-2.5 5.9-3.8 3.9-2.6 7.9-4.9 11.9-7.4 2-1.2 4-2.3 6-3.5l3-1.7 3-1.7q3-1.7 6-3.3c2-1.1 4-2.1 6.1-3.2 1-0.5 2-1.1 3-1.6q1.5-0.8 3-1.5c2-1 4-2 6.1-3 4.1-1.9 8.1-3.8 12.2-5.6 4.1-1.8 8.2-3.4 12.3-5.1 2-0.8 4.1-1.5 6.1-2.3 1-0.4 2-0.8 3.1-1.1 1-0.3 2.1-0.7 3.1-1 8.2-2.9 16.4-5.2 24.5-7.3 2-0.5 4.1-1 6.1-1.4 2-0.4 4.1-0.8 6.1-1.2 2-0.4 4-0.7 6.1-1.1 2-0.3 4-0.7 6-0.9 16-2.2 31.7-2.4 46.5-0.6 1.8 0.3 3.7 0.5 5.5 0.8 1.8 0.3 3.6 0.7 5.4 1 1.8 0.3 3.5 0.8 5.3 1.2 1.7 0.4 3.5 0.8 5.2 1.3q2.5 0.7 5.1 1.5c1.7 0.6 3.3 1.2 4.9 1.8q1.2 0.4 2.4 0.9c0.8 0.3 1.6 0.7 2.4 1 0.8 0.3 1.6 0.7 2.4 1 0.8 0.3 1.6 0.6 2.3 1 12.3 5.8 23.2 13 32.4 21.3 9.3 8.2 17.2 17.2 23.8 26.3 6.6 9.1 12.1 18.3 16.7 27 1.1 2.2 2.2 4.4 3.2 6.5 0.5 1.1 1.1 2.1 1.5 3.2 0.5 1.1 0.9 2.1 1.4 3.2 0.9 2.1 1.8 4.1 2.7 6.1 0.8 2 1.6 4 2.4 5.9 1.6 3.8 2.9 7.6 4.2 11 1.3 3.5 2.3 6.8 3.3 9.9 0.5 1.5 1 3 1.4 4.5 0.5 1.4 0.8 2.8 1.2 4.1 0.8 2.6 1.4 5 2 7.1 0.3 1 0.6 2.1 0.8 3.1 0.3 1 0.5 1.9 0.7 2.8 0.4 1.7 0.8 3.2 1.1 4.3 0 0.2 0.1 0.3 0.1 0.4l5.3 1.9 26.4-7.1c0 0-0.3-1.2-1-3.5-0.3-1.2-0.7-2.6-1.2-4.3-0.2-0.9-0.5-1.8-0.8-2.8-0.3-1-0.6-2-0.9-3.2-0.7-2.4-1.6-5-2.5-7.9-0.5-1.4-0.9-3-1.5-4.5-0.5-1.5-1.1-3.1-1.7-4.8-1.2-3.3-2.4-6.9-3.9-10.7-1.5-3.8-3-7.8-4.9-12-0.9-2.1-1.8-4.3-2.8-6.5-1-2.2-2.1-4.4-3.2-6.7-0.5-1.1-1.1-2.3-1.7-3.5-0.6-1.2-1.2-2.3-1.8-3.5-1.2-2.4-2.5-4.8-3.8-7.2-5.5-9.7-11.9-20-19.8-30.3-7.9-10.3-17.4-20.7-28.8-30.2-11.3-9.6-24.7-18-39.7-24.6-0.9-0.4-1.9-0.8-2.8-1.2-1-0.4-1.9-0.8-2.9-1.1-1-0.4-1.9-0.8-2.9-1.1-1-0.4-2-0.7-3-1-2-0.6-4-1.3-6-1.9-2-0.6-4.1-1.1-6.1-1.7-2-0.6-4.1-1-6.2-1.4-2.1-0.4-4.2-0.9-6.3-1.2-2.1-0.3-4.2-0.7-6.4-1-2.1-0.2-4.3-0.5-6.5-0.7-17.3-1.7-35.2-1-53 1.9-2.2 0.3-4.5 0.8-6.7 1.2-2.2 0.4-4.5 0.8-6.7 1.4-2.2 0.5-4.4 1-6.7 1.5-2.2 0.6-4.4 1.2-6.6 1.7-8.8 2.4-17.7 5.2-26.4 8.5q-1.7 0.6-3.3 1.2c-1.1 0.4-2.2 0.9-3.3 1.3-2.2 0.9-4.4 1.7-6.5 2.6-4.3 1.9-8.6 3.7-12.9 5.7-4.3 2-8.5 4.1-12.8 6.2q-3.2 1.6-6.3 3.3c-1.1 0.6-2.1 1.1-3.2 1.7-1.1 0.6-2.1 1.2-3.1 1.7-2.1 1.2-4.2 2.3-6.3 3.5-2.1 1.2-4.1 2.4-6.2 3.7l-3.1 1.8-3.1 1.9c-2.1 1.3-4.1 2.5-6.2 3.8-4.1 2.6-8.2 5.2-12.2 8-2 1.4-4.1 2.7-6 4.1q-3 2.1-6 4.2c-2 1.4-4 2.9-6 4.3-2 1.5-4 2.9-5.9 4.4-3.9 3-7.8 6-11.7 9.1-7.8 6.1-15.4 12.5-22.9 19-15 13.1-29.5 26.9-43.4 41.4q-2.4 2.5-4.8 5.1z"/>
|
||||
<path id="<Path>" class="s0" d="m157.7 674.4c-2.1-0.6-4.2-1.3-6.4-1.9-1.1-0.3-2.2-0.6-3.3-1-1.1-0.4-2.2-0.8-3.4-1.2-2.3-0.8-4.6-1.6-7-2.4-2.3-0.9-4.7-1.8-7.2-2.8-1.2-0.5-2.5-0.9-3.7-1.5-1.2-0.5-2.5-1.1-3.7-1.6-1.2-0.5-2.5-1.1-3.8-1.6-0.6-0.3-1.3-0.6-1.9-0.8-0.6-0.3-1.3-0.6-1.9-0.9-2.5-1.2-5.1-2.5-7.8-3.8q-3.9-2.1-7.8-4.2c-10.5-5.9-21.2-13-31.5-21.7-10.3-8.7-20-19.1-28.5-31.1l-0.8-1.1-0.8-1.2c-0.5-0.8-1-1.6-1.5-2.3-0.5-0.8-1-1.6-1.5-2.3-0.3-0.4-0.5-0.8-0.8-1.2l-0.7-1.2c-0.9-1.6-1.9-3.3-2.8-4.9-0.5-0.8-0.9-1.7-1.3-2.5-0.4-0.8-0.9-1.7-1.3-2.5-0.4-0.9-0.9-1.7-1.3-2.6-0.5-0.8-0.8-1.7-1.2-2.6-0.8-1.8-1.6-3.5-2.4-5.3-0.7-1.8-1.4-3.6-2.1-5.5-0.3-0.9-0.7-1.8-1-2.8-0.3-0.9-0.6-1.9-0.9-2.8-0.3-0.9-0.6-1.9-0.9-2.8l-0.5-1.4c-0.2-0.5-0.3-1-0.4-1.4-0.5-1.9-1.1-3.9-1.6-5.8-0.3-1-0.5-2-0.7-2.9-0.2-1-0.4-2-0.7-3-0.2-1-0.4-2-0.7-3-0.2-1-0.4-2-0.5-3-1.6-8-2.4-16.3-3-24.7-1-16.8 0.1-34.2 2.7-51.7 0.4-2.2 0.7-4.4 1.1-6.6q0.6-3.3 1.2-6.6 0.3-1.7 0.6-3.3c0.2-1.1 0.5-2.2 0.7-3.3q0.8-3.3 1.5-6.6c1.1-4.4 2.2-8.8 3.5-13.2q0.5-1.7 0.9-3.3c0.3-1.1 0.6-2.2 1-3.3 0.7-2.2 1.4-4.4 2-6.6 0.7-2.2 1.5-4.4 2.2-6.6 0.7-2.2 1.5-4.4 2.3-6.6q1.2-3.3 2.4-6.6c0.8-2.2 1.7-4.4 2.5-6.5l1.3-3.3 1.4-3.3c0.9-2.2 1.8-4.3 2.7-6.5 1-2.2 1.9-4.3 2.9-6.5 0.5-1.1 0.9-2.2 1.4-3.2l1.5-3.2c3.3-7.2 6.8-14.2 10.5-21.3-1.5-6.2-2.9-12.4-4.2-18.7-1.5 2.9-3 5.8-4.4 8.7-4.3 8.8-8.6 17.6-12.4 26.6l-1.5 3.3c-0.5 1.1-0.9 2.2-1.4 3.4-0.9 2.2-1.8 4.5-2.8 6.7-0.9 2.3-1.7 4.5-2.6 6.7l-1.3 3.4-1.2 3.4c-0.8 2.3-1.6 4.5-2.4 6.8-0.8 2.3-1.5 4.5-2.3 6.8-0.8 2.3-1.5 4.5-2.2 6.8-0.7 2.3-1.4 4.5-2.1 6.8-0.6 2.3-1.3 4.5-1.9 6.8-0.3 1.1-0.6 2.3-0.9 3.4-0.3 1.1-0.6 2.3-0.9 3.4-1.2 4.5-2.2 9.1-3.2 13.6-0.5 2.3-0.9 4.6-1.4 6.8-0.2 1.1-0.4 2.3-0.7 3.4-0.2 1.1-0.4 2.3-0.6 3.4-0.4 2.3-0.8 4.5-1.1 6.8-0.3 2.3-0.6 4.5-0.9 6.8-2.3 18.1-2.9 36.1-1.4 53.4 0.8 8.7 1.9 17.2 3.7 25.5 0.2 1 0.4 2.1 0.6 3.1 0.3 1 0.5 2 0.8 3.1 0.3 1 0.5 2 0.8 3 0.3 1 0.5 2 0.8 3q0.9 3 1.8 6c0.2 0.5 0.3 1 0.5 1.5l0.5 1.5c0.3 1 0.7 1.9 1 2.9 0.3 1 0.7 1.9 1 2.9 0.3 1 0.8 1.9 1.1 2.8 0.8 1.9 1.6 3.7 2.3 5.6 0.9 1.8 1.7 3.6 2.6 5.4 0.4 0.9 0.8 1.8 1.3 2.7 0.5 0.9 0.9 1.7 1.4 2.6 0.5 0.9 0.9 1.7 1.4 2.6 0.5 0.9 0.9 1.7 1.5 2.6 1 1.7 2 3.3 3 5l0.8 1.2c0.3 0.4 0.5 0.8 0.8 1.2 0.5 0.8 1.1 1.6 1.6 2.4 0.5 0.8 1.1 1.6 1.6 2.4l0.8 1.2 0.9 1.1c9.1 12.2 19.4 22.6 30.1 31.2 10.8 8.6 21.8 15.6 32.6 21.3 2.7 1.4 5.4 2.7 8 4.1 2.7 1.2 5.3 2.4 7.9 3.6 0.6 0.3 1.3 0.6 1.9 0.9 0.7 0.3 1.3 0.5 2 0.8 1.3 0.5 2.6 1 3.9 1.6 1.3 0.5 2.5 1 3.8 1.5 1.2 0.5 2.5 0.9 3.8 1.4 2.5 0.9 4.9 1.8 7.3 2.6 2.4 0.8 4.8 1.5 7.1 2.2 1.2 0.4 2.3 0.7 3.4 1.1 1.1 0.4 2.3 0.6 3.4 1 2.2 0.6 4.4 1.2 6.5 1.8 16.9 4.5 30.4 6.7 39.7 8.3 9.3 1.3 14.2 2 14.2 2 0 0-4.9-0.8-14.1-2.4-9.1-2-22.5-4.6-39.3-9.4z"/>
|
||||
</g>
|
||||
<g id="<Group>">
|
||||
<g id="<Group>">
|
||||
</g>
|
||||
<g id="<Group>">
|
||||
<path id="<Path>" class="s1" d="m294.7 337.1v326.6c19.1 18.4 35.9 32.8 48.1 42.8 12.2-10 29-24.4 48.1-42.8v-326.6h199.8c8-30.4 13.7-62.5 16.3-96.1h-528.4c2.6 33.6 8.4 65.7 16.3 96.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="<Group>">
|
||||
<path id="<Compound Path>" fill-rule="evenodd" class="s1" d="m342.8 778.5l-11-7.6c-3.2-2.2-79.3-55.6-156.2-152.6-45.3-57.1-81.4-117.4-107.3-179.4-32.5-77.8-49-158.4-49-239.5v-13.7l323.5-112.5 323.5 112.5v13.7c0 81.1-16.5 161.6-49 239.5-25.9 62-62 122.4-107.3 179.4-76.9 97-153 150.4-156.2 152.6zm-284.9-565.6c4.1 165.5 81.7 297.8 147.1 380.5 56.8 71.9 114.4 119.6 137.8 137.7 23.5-18.1 81-65.8 137.8-137.7 65.4-82.7 143-215 147.1-380.5l-284.9-99z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
44
assets/custom-icons/icons/uphold.svg
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 96 96"
|
||||
xml:space="preserve"
|
||||
id="svg1"
|
||||
sodipodi:docname="uphold.svg"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="8.09375"
|
||||
inkscape:cx="48"
|
||||
inkscape:cy="48"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="991"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<desc
|
||||
id="desc1">Created with Fabric.js 5.3.0</desc>
|
||||
<g
|
||||
transform="matrix(1.6496133,0,0,1.6496134,47.999993,48.000007)"
|
||||
id="RoQhZNvyF1biObpr9w5El">
|
||||
<path
|
||||
style="opacity:1;fill:#6fe68a;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
d="m 3.59732,16.89848 c -1.1,0.4 -2.3,0.5 -3.5,0.5 h -0.2 c -1.2,0 -2.4,-0.2 -3.5,-0.6 -0.6,-0.2 -1.1,0.2 -1.3,0.7 -0.2,0.6 0.2,1.2 0.7,1.3 1.3,0.4 2.7,0.6 4.1,0.6 h 0.2 c 1.4,0 2.8,-0.2 4.1,-0.6 0.5,-0.2 0.8,-0.8 0.6,-1.4 -0.2,-0.3 -0.7,-0.6 -1.2,-0.5 z m 9.1,-26.7 c 0,0 0,-0.1 0,0 -2.3,-7.3 -9.9,-11.3 -16.9,-8.9 -4,1.4 -7.2,4.7 -8.5,8.9 -1.2,3.6 -0.8,8.4 1.2,12.9 2.6,6.1 7.3,10.4 11.5,10.4 h 0.1 c 4.2,0 8.9,-4.3 11.5,-10.4 1.9,-4.5 2.3,-9.3 1.1,-12.9 m -6.2,-5.2 c -2.1,-0.1 -4.4,0.9 -6.6,2.7 -2.2,-1.8 -4.5,-2.8 -6.6,-2.7 4,-2.9 9.3,-2.9 13.2,0 m -4.8,25.9 c -1.1,0.5 -2.4,0.5 -3.5,0 -3.6,-1.7 -4.3,-8.6 -1.6,-14.9 0.8,-2 1.9,-3.8 3.3,-5.3 1.4,1.6 2.5,3.4 3.3,5.3 2.8,6.4 2.1,13.2 -1.5,14.9 m -11.4,-8.7 c -1.7,-4 -2.1,-8.2 -1.1,-11.4 0.5,-1.6 1.5,-2.8 2.7,-3.4 1.8,-0.8 4.2,-0.1 6.6,1.8 -1.5,1.8 -2.8,3.8 -3.7,5.9 -1.8,4.3 -2.2,8.8 -1.4,12.2 -1.3,-1.5 -2.3,-3.2 -3.1,-5.1 m 19.3,0 c -0.8,1.8 -1.8,3.5 -3,5.1 0.8,-3.4 0.4,-7.9 -1.4,-12.2 -0.9,-2.2 -2.2,-4.2 -3.7,-5.9 2.3,-1.9 4.7,-2.6 6.6,-1.7 1.2,0.6 2.1,1.7 2.7,3.4 0.9,3.1 0.5,7.3 -1.2,11.3 z"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -79,6 +79,8 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- privacy_screen (0.0.1):
|
||||
- Flutter
|
||||
- qr_code_scanner (0.2.0):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner
|
||||
@@ -127,6 +129,7 @@ DEPENDENCIES:
|
||||
- open_filex (from `.symlinks/plugins/open_filex/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- privacy_screen (from `.symlinks/plugins/privacy_screen/ios`)
|
||||
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
|
||||
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
@@ -186,6 +189,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
privacy_screen:
|
||||
:path: ".symlinks/plugins/privacy_screen/ios"
|
||||
qr_code_scanner:
|
||||
:path: ".symlinks/plugins/qr_code_scanner/ios"
|
||||
sentry_flutter:
|
||||
@@ -225,6 +230,7 @@ SPEC CHECKSUMS:
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"account": "Konto",
|
||||
"unlock": "Entsperren",
|
||||
"recoveryKey": "Wiederherstellungsschlüssel",
|
||||
"counterAppBarTitle": "Zähler",
|
||||
"@counterAppBarTitle": {
|
||||
@@ -60,6 +61,7 @@
|
||||
"contactSupport": "Support kontaktieren",
|
||||
"rateUsOnStore": "Bewerte uns auf {storeName}",
|
||||
"blog": "Blog",
|
||||
"merchandise": "Merchandise",
|
||||
"verifyPassword": "Passwort überprüfen",
|
||||
"pleaseWait": "Bitte warten...",
|
||||
"generatingEncryptionKeysTitle": "Generierung von Verschlüsselungsschlüsseln...",
|
||||
@@ -75,12 +77,14 @@
|
||||
"changePassword": "Passwort ändern",
|
||||
"data": "Datei",
|
||||
"importCodes": "Codes importieren",
|
||||
"importTypePlainText": "Klartext",
|
||||
"importTypeEnteEncrypted": "ente verschlüsselt exportieren",
|
||||
"passwordForDecryptingExport": "Passwort um den Export zu entschlüsseln",
|
||||
"passwordEmptyError": "Passwort kann nicht leer sein",
|
||||
"importFromApp": "Importiere Codes von {appName}",
|
||||
"importGoogleAuthGuide": "Exportiere deine Accounts von Google Authenticator zu einem QR-Code, durch die \"Konten übertragen\" Option. Scanne den QR-Code danach mit einem anderen Gerät.\n\nTipp: Du kannst die Kamera eines Laptops verwenden, um ein Foto den dem QR-Code zu erstellen.",
|
||||
"importSelectJsonFile": "Wähle eine JSON-Datei",
|
||||
"importSelectAppExport": "{appName} Exportdatei auswählen",
|
||||
"importEnteEncGuide": "Wähle die von ente exportierte, verschlüsselte JSON-Datei",
|
||||
"exportCodes": "Codes exportieren",
|
||||
"importLabel": "Importieren",
|
||||
@@ -92,6 +96,7 @@
|
||||
"authToViewYourRecoveryKey": "Bitte authentifizieren um ihren Wiederherstellungscode anzuzeigen",
|
||||
"authToChangeYourEmail": "Bitte authentifizieren um ihre Emailadresse zu ändern",
|
||||
"authToChangeYourPassword": "Bitte authentifizieren um ihr Passwort zu ändern",
|
||||
"authToViewSecrets": "Bitte authentifizieren Sie sich, um ihren Wiederherstellungscode anzuzeigen",
|
||||
"ok": "Ok",
|
||||
"cancel": "Abbrechen",
|
||||
"yes": "Ja",
|
||||
@@ -177,6 +182,7 @@
|
||||
"enterDetailsManually": "Details manuell hinzufügen",
|
||||
"edit": "Editieren",
|
||||
"copiedToClipboard": "In die Zwischenablage kopieren",
|
||||
"copiedNextToClipboard": "Nächster Code wurde in die Zwischenablage kopiert",
|
||||
"error": "Fehler",
|
||||
"recoveryKeyCopiedToClipboard": "Wiederherstellungsschlüssel in die Zwischenablage kopiert",
|
||||
"recoveryKeyOnForgotPassword": "Sollten sie ihr Passwort vergessen, dann ist dieser Schlüssel die einzige Möglichkeit ihre Daten wiederherzustellen.",
|
||||
@@ -309,7 +315,68 @@
|
||||
"incorrectRecoveryKey": "Falscher Wiederherstellungs-Schlüssel",
|
||||
"theRecoveryKeyYouEnteredIsIncorrect": "Der eingegebene Wiederherstellungs-Schlüssel ist ungültig",
|
||||
"enterPassword": "Passwort eingeben",
|
||||
"selectExportFormat": "Exportformat auswählen",
|
||||
"encrypted": "Verschlüsselt",
|
||||
"plainText": "Klartext",
|
||||
"passwordToEncryptExport": "Passwort zum Verschlüssen des Exports",
|
||||
"export": "Export",
|
||||
"useOffline": "Ohne Backup verwenden",
|
||||
"signInToBackup": "Melde dich an, um deine Codes zu sichern",
|
||||
"singIn": "Anmelden",
|
||||
"showLargeIcons": "Große Symbole anzeigen",
|
||||
"shouldHideCode": "Codes ausblenden",
|
||||
"doubleTapToViewHiddenCode": "Sie können auf einen Eintrag doppelt tippen, um den Code anzuzeigen",
|
||||
"minimizeAppOnCopy": "Beim Kopieren App minimieren",
|
||||
"editCodeAuthMessage": "Authentifizieren, um Code zu bearbeiten",
|
||||
"deleteCodeAuthMessage": "Authentifizieren, um Code zu löschen",
|
||||
"showQRAuthMessage": "Authentifizieren, um QR-Code anzuzeigen"
|
||||
"showQRAuthMessage": "Authentifizieren, um QR-Code anzuzeigen",
|
||||
"confirmAccountDeleteTitle": "Kontolöschung bestätigen",
|
||||
"androidBiometricHint": "Identität bestätigen",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Nicht erkannt. Versuchen Sie es erneut.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Erfolgreich",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "Abbrechen",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "Authentifizierung erforderlich",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricRequiredTitle": "Biometrie erforderlich",
|
||||
"@androidBiometricRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsRequiredTitle": "Geräteanmeldeinformationen erforderlich",
|
||||
"@androidDeviceCredentialsRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsSetupDescription": "Geräteanmeldeinformationen erforderlich",
|
||||
"@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": "Zu den Einstellungen",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"iOSOkButton": "OK",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"noInternetConnection": "Keine Internetverbindung",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Bitte überprüfe deine Internetverbindung und versuche es erneut.",
|
||||
"signOutFromOtherDevices": "Von anderen Geräten abmelden",
|
||||
"signOutOtherBody": "Falls du denkst, dass jemand dein Passwort kennen könnte, kannst du alle anderen Geräte von deinem Account abmelden.",
|
||||
"signOutOtherDevices": "Andere Geräte abmelden",
|
||||
"doNotSignOut": "Nicht abmelden",
|
||||
"hearUsWhereTitle": "Wie hast du von Ente erfahren? (optional)",
|
||||
"hearUsExplanation": "Wir tracken keine App-Installationen. Es würde uns jedoch helfen, wenn du uns mitteilst, wie du von uns erfahren hast!"
|
||||
}
|
||||
@@ -96,7 +96,7 @@
|
||||
"importCodeDelimiterInfo": "The codes can be separated by a comma or a new line",
|
||||
"selectFile": "Select file",
|
||||
"emailVerificationToggle": "Email verification",
|
||||
"emailVerificationEnableWarning": "If you are storing the 2FA to your email with us, turning on email verification could result in a deadlock. If you are locked out of one service, you might not be able to log in to the other.",
|
||||
"emailVerificationEnableWarning": "To avoid getting locked out of your account, be sure to store a copy of your email 2FA outside of Ente Auth before enabling email verification.",
|
||||
"authToChangeEmailVerificationSetting": "Please authenticate to change email verification",
|
||||
"authToViewYourRecoveryKey": "Please authenticate to view your recovery key",
|
||||
"authToChangeYourEmail": "Please authenticate to change your email",
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
"importScanQrCode": "QR კოდის დასკანერება",
|
||||
"qrCode": "QR კოდი",
|
||||
"importEnterSetupKey": "შეიყვანეთ დაყენების კოდი",
|
||||
"importAccountPageTitle": "შეიყვანეთ ანგარიშის დეტალები",
|
||||
"importAccountPageTitle": "შეიყვანეთ ანგარიშის მონაცემები",
|
||||
"secretCanNotBeEmpty": "გასაღების ველი არ შეიძლება ცარიელი იყოს",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "ანგარიშის მომწოდებლისა და ანგარიშის ველი არ შეიძლება ცარიელი იყოს",
|
||||
"bothIssuerAndAccountCanNotBeEmpty": "მომწოდებლისა და ანგარიშის ველი არ შეიძლება ცარიელი იყოს",
|
||||
"incorrectDetails": "არასწორი მონაცემები",
|
||||
"pleaseVerifyDetails": "გთხოვთ, გადაამოწმოთ დეტალები და სცადოთ ხელახლა",
|
||||
"pleaseVerifyDetails": "გთხოვთ, გადაამოწმოთ მონაცემები და სცადოთ ხელახლა",
|
||||
"codeIssuerHint": "მომწოდებელი",
|
||||
"codeSecretKeyHint": "გასაღები",
|
||||
"codeAccountHint": "ანგარიში (you@domain.com)",
|
||||
@@ -88,5 +88,29 @@
|
||||
"copied": "დაკოპირებულია",
|
||||
"pleaseTryAgain": "გთხოვთ, სცადოთ ხელახლა",
|
||||
"existingUser": "არსებული მომხმარებელი",
|
||||
"delete": "წაშლა"
|
||||
"delete": "წაშლა",
|
||||
"androidBiometricNotRecognized": "ამოცნობა ვერ მოხერხდა. გთხოვთ, სცადოთ ხელახლა.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "წარმატებით",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "გაუქმება",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "საჭიროა აუთენთიფიკაცია",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"noInternetConnection": "ინტერნეტთან კავშირი არ არის",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "გთხოვთ, შეამოწმოთ თქვენი ინტერნეტ კავშირი და სცადოთ ხელახლა.",
|
||||
"signOutFromOtherDevices": "ყველა მოწყობილობიდან გამოსვლა",
|
||||
"signOutOtherBody": "თუ ფიქრობთ, რომ ვინმემ შესაძლოა იცოდეს თქვენი პაროლი, შეგიძლიათ ყველა მოწყობილობაზე იძულებითი გამოსვლა, რომელიც იყენებს თქვენს ანგარიშს.",
|
||||
"signOutOtherDevices": "სხვა მოწყობილობებიდან გამოსვლა",
|
||||
"doNotSignOut": "არ მოხდეს გამოსვლა",
|
||||
"hearUsWhereTitle": "როგორ შეიტყვეთ Ente-ს შესახებ? (არასავალდებულო)",
|
||||
"hearUsExplanation": "ჩვენ არ ვაკონტროლებთ აპლიკაციის ინსტალაციას. სასარგებლო იქნებოდა, თუ გვეტყოდით, სად გვიპოვეთ!"
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"account": "Account",
|
||||
"unlock": "Ontgrendelen",
|
||||
"recoveryKey": "Herstelsleutel",
|
||||
"counterAppBarTitle": "Teller",
|
||||
"@counterAppBarTitle": {
|
||||
@@ -83,9 +84,12 @@
|
||||
"importFromApp": "Importeer codes van {appName}",
|
||||
"importGoogleAuthGuide": "Exporteer uw accounts van Google Authenticator naar een QR-code met behulp van de optie \"Transfer Accounts\". Met een ander apparaat scan je de QR-code.\n\nTip: Je kunt de webcam van je laptop gebruiken om een foto van de QR-code te maken.",
|
||||
"importSelectJsonFile": "Selecteer JSON bestand",
|
||||
"importSelectAppExport": "Selecteer {appName} exportbestand",
|
||||
"importEnteEncGuide": "Selecteer het versleutelde JSON-bestand dat vanuit ente geëxporteerd is",
|
||||
"importRaivoGuide": "Gebruik de optie \"Export OTPs to Zip archive\" in Raivo's instellingen.\n\nPak het zip-bestand uit en importeer het JSON-bestand.",
|
||||
"importBitwardenGuide": "Gebruik de optie \"Exporteer kluis\" binnen Bitwarden Tools en importeer het niet-versleutelde JSON-bestand.",
|
||||
"importAegisGuide": "Gebruik de optie \"Exporteer de kluis\" in de instellingen van Aegis.\n\nAls uw kluis is versleuteld, moet u het wachtwoord invoeren om de kluis te ontsleutelen.",
|
||||
"import2FasGuide": "Gebruik de optie \"Instellingen->Backup -Export\" in 2FAS.\n\nAls uw back-up is versleuteld, moet u het wachtwoord invoeren om de back-up te ontsleutelen",
|
||||
"exportCodes": "Codes exporteren",
|
||||
"importLabel": "Importeren",
|
||||
"importInstruction": "Selecteer een bestand dat een lijst van uw codes in de volgende indeling bevat",
|
||||
@@ -97,6 +101,8 @@
|
||||
"authToViewYourRecoveryKey": "Graag verifiëren om uw herstelsleutel te bekijken",
|
||||
"authToChangeYourEmail": "Graag verifiëren om je e-mailadres te wijzigen",
|
||||
"authToChangeYourPassword": "Graag verifiëren om je wachtwoord te wijzigen",
|
||||
"authToViewSecrets": "Graag verifiëren om uw herstelsleutel te bekijken",
|
||||
"authToInitiateSignIn": "Verifiëren om in te kunnen loggen voor back-up.",
|
||||
"ok": "Oké",
|
||||
"cancel": "Annuleer",
|
||||
"yes": "Ja",
|
||||
@@ -329,6 +335,7 @@
|
||||
"offlineModeWarning": "Je hebt ervoor gekozen om verder te gaan zonder back-ups. Neem handmatige back-ups om ervoor te zorgen dat jouw codes veilig zijn.",
|
||||
"showLargeIcons": "Grote iconen",
|
||||
"shouldHideCode": "Verberg codes",
|
||||
"doubleTapToViewHiddenCode": "Je kunt dubbel klikken op een item om code te bekijken",
|
||||
"focusOnSearchBar": "Focus zoekveld na starten app",
|
||||
"confirmUpdatingkey": "Weet u zeker dat u de geheime sleutel wilt bijwerken?",
|
||||
"minimizeAppOnCopy": "Na kopiëren app minimaliseren",
|
||||
@@ -336,5 +343,65 @@
|
||||
"deleteCodeAuthMessage": "Authenticeren om code te verwijderen",
|
||||
"showQRAuthMessage": "Authenticeren om QR-code te tonen",
|
||||
"confirmAccountDeleteTitle": "Account verwijderen bevestigen",
|
||||
"confirmAccountDeleteMessage": "Dit account is gekoppeld aan andere ente apps, als je er gebruik van maakt.\n\nJe geüploade gegevens worden in alle ente apps gepland voor verwijdering, en je account wordt permanent verwijderd voor alle ente diensten."
|
||||
"confirmAccountDeleteMessage": "Dit account is gekoppeld aan andere ente apps, als je er gebruik van maakt.\n\nJe geüploade gegevens worden in alle ente apps gepland voor verwijdering, en je account wordt permanent verwijderd voor alle ente diensten.",
|
||||
"androidBiometricHint": "Identiteit verifiëren",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Niet herkend. Probeer het opnieuw.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Succes",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "Annuleren",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "Verificatie vereist",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricRequiredTitle": "Biometrische verificatie vereist",
|
||||
"@androidBiometricRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsRequiredTitle": "Apparaatgegevens vereist",
|
||||
"@androidDeviceCredentialsRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsSetupDescription": "Apparaatgegevens vereist",
|
||||
"@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": "Ga naar instellingen",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"androidGoToSettingsDescription": "Biometrische verificatie is niet ingesteld op uw apparaat. Ga naar 'Instellingen > Beveiliging' om biometrische verificatie toe te voegen.",
|
||||
"@androidGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"iOSLockOut": "Biometrische verificatie is uitgeschakeld. Vergrendel en ontgrendel uw scherm om het in te schakelen.",
|
||||
"@iOSLockOut": {
|
||||
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSGoToSettingsDescription": "Biometrische authenticatie is niet ingesteld op uw apparaat. Schakel Touch ID of Face ID in op uw telefoon.",
|
||||
"@iOSGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSOkButton": "Oké",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"noInternetConnection": "Geen internetverbinding",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Controleer je internetverbinding en probeer het opnieuw.",
|
||||
"signOutFromOtherDevices": "Afmelden bij andere apparaten",
|
||||
"signOutOtherBody": "Als je denkt dat iemand je wachtwoord zou kunnen kennen, kun je alle andere apparaten die je account gebruiken dwingen om uit te loggen.",
|
||||
"signOutOtherDevices": "Afmelden bij andere apparaten",
|
||||
"doNotSignOut": "Niet uitloggen",
|
||||
"hearUsWhereTitle": "Hoe hoorde je over Ente? (optioneel)",
|
||||
"hearUsExplanation": "Wij gebruiken geen tracking. Het zou helpen als je ons vertelt waar je ons gevonden hebt!"
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"account": "Konto",
|
||||
"unlock": "Odblokuj",
|
||||
"recoveryKey": "Klucz odzyskiwania",
|
||||
"counterAppBarTitle": "Licznik",
|
||||
"@counterAppBarTitle": {
|
||||
@@ -97,6 +98,7 @@
|
||||
"authToViewYourRecoveryKey": "Proszę uwierzytelnić, aby wyświetlić swój klucz odzyskiwania",
|
||||
"authToChangeYourEmail": "Proszę uwierzytelnić, aby zmienić swój adres e-mail",
|
||||
"authToChangeYourPassword": "Proszę uwierzytelnić, aby zmienić hasło",
|
||||
"authToViewSecrets": "Proszę uwierzytelnić, aby wyświetlić swoje sekrety",
|
||||
"ok": "Ok",
|
||||
"cancel": "Anuluj",
|
||||
"yes": "Tak",
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
{
|
||||
"account": "Tài khoản",
|
||||
"unlock": "Mở khóa",
|
||||
"recoveryKey": "Khóa khôi phục",
|
||||
"counterAppBarTitle": "Bộ Đếm",
|
||||
"@counterAppBarTitle": {
|
||||
"description": "Text shown in the AppBar of the Counter Page"
|
||||
},
|
||||
"onBoardingBody": "Bảo mật mã 2FA của bạn",
|
||||
"onBoardingBody": "Sao lưu an toàn mã 2FA của bạn",
|
||||
"onBoardingGetStarted": "Bắt đầu",
|
||||
"setupFirstAccount": "Thiết lập tài khoản đầu tiên của bạn",
|
||||
"importScanQrCode": "Quét mã QR",
|
||||
"qrCode": "Mã QR",
|
||||
"importEnterSetupKey": "Nhập khóa thiết lập",
|
||||
"importAccountPageTitle": "Nhập chi tiết tài khoản",
|
||||
"secretCanNotBeEmpty": "Khoá bí mật không được để trống",
|
||||
@@ -46,7 +48,7 @@
|
||||
"copyEmailAction": "Sao chép email",
|
||||
"exportLogsAction": "Xuất nhật ký",
|
||||
"reportABug": "Báo cáo lỗi",
|
||||
"crashAndErrorReporting": "Báo cáo sự cố và lỗi",
|
||||
"crashAndErrorReporting": "Báo cáo sự cố & lỗi",
|
||||
"reportBug": "Báo lỗi",
|
||||
"emailUsMessage": "Vui lòng gửi email cho chúng tôi tại {email}",
|
||||
"@emailUsMessage": {
|
||||
@@ -57,11 +59,14 @@
|
||||
}
|
||||
},
|
||||
"contactSupport": "Liên hệ hỗ trợ",
|
||||
"rateUsOnStore": "Đánh giá chúng tôi trên {storeName}",
|
||||
"blog": "Blog",
|
||||
"merchandise": "Hàng hóa",
|
||||
"verifyPassword": "Xác nhận mật khẩu",
|
||||
"pleaseWait": "Vui lòng chờ...",
|
||||
"generatingEncryptionKeysTitle": "Đang tạo khóa mã hóa...",
|
||||
"recreatePassword": "Tạo lại mật khẩu",
|
||||
"recreatePasswordMessage": "Thiết bị hiện tại không đủ mạnh để xác minh mật khẩu của bạn, vì vậy chúng tôi cần tạo lại mật khẩu một lần theo cách hoạt động với tất cả các thiết bị. \n\nVui lòng đăng nhập bằng khóa khôi phục và tạo lại mật khẩu của bạn (bạn có thể sử dụng lại cùng một mật khẩu nếu muốn).",
|
||||
"recreatePasswordMessage": "Thiết bị hiện tại không đủ mạnh để xác minh mật khẩu của bạn, vì vậy chúng tôi cần tạo lại mật khẩu một lần theo cách hoạt động với tất cả các thiết bị.\n\nVui lòng đăng nhập bằng khóa khôi phục và tạo lại mật khẩu của bạn (bạn có thể sử dụng lại cùng một mật khẩu nếu muốn).",
|
||||
"useRecoveryKey": "Dùng khóa khôi phục",
|
||||
"incorrectPasswordTitle": "Mật khẩu không đúng",
|
||||
"welcomeBack": "Chào mừng trở lại!",
|
||||
@@ -72,19 +77,39 @@
|
||||
"changePassword": "Thay đổi mật khẩu",
|
||||
"data": "Dữ liệu",
|
||||
"importCodes": "Nhập mã",
|
||||
"importTypePlainText": "Văn bản thuần",
|
||||
"importTypeEnteEncrypted": "xuất ente đã mã hóa",
|
||||
"passwordForDecryptingExport": "Mật khẩu để giải mã xuất",
|
||||
"passwordEmptyError": "Mật khẩu không thể để trống",
|
||||
"importFromApp": "Nhập mã từ {appName}",
|
||||
"importGoogleAuthGuide": "Xuất dữ liệu tài khoản của bạn từ Google Authenticator sang mã QR bằng tùy chọn \"Chuyển tài khoản\". Sau đó dùng thiết bị khác quét mã QR.",
|
||||
"importSelectJsonFile": "Chọn tệp JSON",
|
||||
"importSelectAppExport": "Chọn {appName} tệp dữ liệu xuất",
|
||||
"importEnteEncGuide": "Chọn tệp JSON được mã hóa đã xuất từ ente",
|
||||
"importRaivoGuide": "Sử dụng tùy chọn \"Xuất OTP sang lưu trữ Zip\" trong cài đặt của Raivo.",
|
||||
"importBitwardenGuide": "Sử dụng tùy chọn \"Xuất vault\" trong công cụ Bitwarden và nhập tệp JSON không được mã hóa.",
|
||||
"importAegisGuide": "Nếu vault của bạn được mã hóa, bạn sẽ cần nhập mật khẩu vault để giải mã vault.",
|
||||
"import2FasGuide": "Sử dụng tùy chọn \"Cài đặt->Sao lưu -Xuất dữ liệu\" trong 2FAS.\n\nNếu bản sao lưu của bạn được mã hóa, bạn sẽ cần nhập mật khẩu để giải mã bản sao lưu",
|
||||
"exportCodes": "Xuất mã",
|
||||
"importLabel": "Nhập",
|
||||
"importInstruction": "Vui lòng chọn tệp chứa danh sách mã của bạn ở định dạng sau",
|
||||
"importCodeDelimiterInfo": "Các mã có thể được phân tách bằng một dấu phẩy hoặc một dòng mới",
|
||||
"selectFile": "Chọn tập tin",
|
||||
"emailVerificationToggle": "Email xác thực",
|
||||
"emailVerificationEnableWarning": "Để tránh bị khóa tài khoản, hãy đảm bảo lưu trữ bản sao email 2FA của bạn bên ngoài Ente Auth trước khi bật xác minh email.",
|
||||
"authToChangeEmailVerificationSetting": "Vui lòng xác thực để thay đổi email",
|
||||
"authToViewYourRecoveryKey": "Vui lòng xác thực để xem khóa khôi phục của bạn",
|
||||
"authToChangeYourEmail": "Vui lòng xác thực để thay đổi email của bạn",
|
||||
"authToChangeYourPassword": "Vui lòng xác thực để thay đổi mật khẩu của bạn",
|
||||
"ok": "Được rồi",
|
||||
"authToViewSecrets": "Vui lòng xác thực để xem bí mật của bạn",
|
||||
"authToInitiateSignIn": "Vui lòng xác thực để bắt đầu đăng nhập nhằm sao lưu.",
|
||||
"ok": "Đồng ý",
|
||||
"cancel": "Hủy",
|
||||
"yes": "Đúng",
|
||||
"no": "Không",
|
||||
"email": "Thư điện tử",
|
||||
"support": "Hỗ trợ",
|
||||
"general": "Tổng quan",
|
||||
"settings": "Cài đặt",
|
||||
"copied": "\u001dĐã sao chép",
|
||||
"pleaseTryAgain": "Vui lòng thử lại",
|
||||
@@ -94,6 +119,18 @@
|
||||
"enterYourPasswordHint": "Nhập mật khẩu của bạn",
|
||||
"forgotPassword": "Quên mật khẩu",
|
||||
"oops": "Rất tiếc",
|
||||
"suggestFeatures": "Tính năng đề nghị",
|
||||
"faq": "Câu hỏi thường gặp",
|
||||
"faq_q_1": "Mức độ an toàn của ente Auth như thế nào?",
|
||||
"faq_a_1": "Tất cả các mã bạn sao lưu qua ente đều được lưu trữ dưới dạng mã hóa đầu cuối. Điều này có nghĩa là chỉ bạn mới có thể truy cập mã của mình. Ứng dụng của chúng tôi là nguồn mở và mật mã của chúng tôi đã được kiểm toán độc lập.",
|
||||
"faq_q_2": "Tôi có thể truy cập mã của mình trên máy tính không?",
|
||||
"faq_a_2": "Bạn có thể truy cập mã của mình trên web @ auth.ente.io.",
|
||||
"faq_q_3": "Làm cách nào để xóa mã?",
|
||||
"faq_a_3": "Bạn có thể xóa mã bằng cách vuốt sang trái vào mục đó.",
|
||||
"faq_q_4": "Tôi có thể hỗ trợ dự án này như thế nào?",
|
||||
"faq_a_4": "Bạn có thể hỗ trợ sự phát triển của dự án này bằng cách đăng ký ứng dụng Ảnh @ ente.io của chúng tôi.",
|
||||
"faq_q_5": "Tôi có thể bật khóa FaceID trong ente Auth như thế nào",
|
||||
"faq_a_5": "Bạn có thể bật khóa FaceID trong Cài đặt → Bảo mật → Màn hình khóa.",
|
||||
"somethingWentWrongMessage": "Phát hiện có lỗi, xin thử lại",
|
||||
"leaveFamily": "Rời khỏi gia đình",
|
||||
"leaveFamilyMessage": "Bạn có chắc chắn muốn thoát khỏi gói dành cho gia đình không?",
|
||||
@@ -152,12 +189,14 @@
|
||||
"enterDetailsManually": "Nhập chi tiết thủ công",
|
||||
"edit": "Sửa",
|
||||
"copiedToClipboard": "Đã sao chép vào khay nhớ tạm",
|
||||
"copiedNextToClipboard": "Đã sao chép mã tiếp theo vào bảng nhớ tạm",
|
||||
"error": "Lỗi",
|
||||
"recoveryKeyCopiedToClipboard": "Đã sao chép khóa khôi phục vào bộ nhớ tạm",
|
||||
"recoveryKeyOnForgotPassword": "Nếu bạn quên mật khẩu, cách duy nhất bạn có thể khôi phục dữ liệu của mình là sử dụng khóa này.",
|
||||
"recoveryKeySaveDescription": "Chúng tôi không lưu trữ khóa này, vui lòng lưu khóa 24 từ này ở nơi an toàn.",
|
||||
"doThisLater": "Để sau",
|
||||
"saveKey": "Lưu khóa",
|
||||
"back": "Quay lại",
|
||||
"createAccount": "Tạo tài khoản",
|
||||
"passwordStrength": "Độ mạnh mật khẩu: {passwordStrengthValue}",
|
||||
"@passwordStrength": {
|
||||
@@ -221,6 +260,10 @@
|
||||
"privacy": "Riêng tư",
|
||||
"terms": "Điều khoản",
|
||||
"checkForUpdates": "Kiểm tra cập nhật",
|
||||
"downloadUpdate": "Tải xuống",
|
||||
"criticalUpdateAvailable": "Đã có bản cập nhật quan trọng",
|
||||
"updateAvailable": "Đã có bản cập nhật",
|
||||
"update": "Cập nhật",
|
||||
"checking": "Đang kiểm tra...",
|
||||
"youAreOnTheLatestVersion": "Bạn đang sử dụng phiên bản mới nhất",
|
||||
"warning": "Cánh báo",
|
||||
@@ -266,7 +309,99 @@
|
||||
"terminateSession": "Chấm dứt phiên?",
|
||||
"terminate": "Dừng lại",
|
||||
"thisDevice": "Thiết bị này",
|
||||
"toResetVerifyEmail": "Để đặt lại mật khẩu, vui lòng xác minh email của bạn trước.",
|
||||
"thisEmailIsAlreadyInUse": "Email này đã được sử dụng",
|
||||
"verificationFailedPleaseTryAgain": "Mã xác nhận thất bại. Vui lòng thử lại",
|
||||
"yourVerificationCodeHasExpired": "Mã xác minh của bạn đã hết hạn",
|
||||
"incorrectCode": "Mã không chính xác",
|
||||
"sorryTheCodeYouveEnteredIsIncorrect": "Xin lỗi, mã bạn đã nhập không chính xác",
|
||||
"emailChangedTo": "Thay đổi email thành {newEmail}",
|
||||
"authenticationFailedPleaseTryAgain": "Xác thực lỗi, vui lòng thử lại",
|
||||
"authenticationSuccessful": "Xác thực thành công!",
|
||||
"twofactorAuthenticationSuccessfullyReset": "Xác thực hai bước được khôi phục thành công",
|
||||
"incorrectRecoveryKey": "Khóa khôi phục không chính xác",
|
||||
"theRecoveryKeyYouEnteredIsIncorrect": "Khóa khôi phục bạn đã nhập không chính xác",
|
||||
"enterPassword": "Nhập mật khẩu",
|
||||
"selectExportFormat": "Chọn định dạng dữ liệu xuất",
|
||||
"exportDialogDesc": "Xuất dữ liệu được mã hóa sẽ được bảo vệ bằng mật khẩu bạn chọn.",
|
||||
"encrypted": "Đã mã hóa",
|
||||
"plainText": "Văn bản thuần",
|
||||
"passwordToEncryptExport": "Mật khẩu để giải mã dữ liệu xuất",
|
||||
"export": "Xuất dữ liệu",
|
||||
"useOffline": "Sử dụng mà không sao lưu",
|
||||
"signInToBackup": "Đăng nhập để sao lưu mã của bạn",
|
||||
"singIn": "Đăng nhập",
|
||||
"sigInBackupReminder": "Vui lòng xuất mã của bạn để đảm bảo rằng bạn có bản sao lưu có thể khôi phục.",
|
||||
"offlineModeWarning": "Bạn đã chọn tiếp tục mà không cần sao lưu. Vui lòng sao lưu thủ công để đảm bảo mã của bạn được an toàn.",
|
||||
"showLargeIcons": "Hiển thị biểu tượng lớn",
|
||||
"shouldHideCode": "Ẩn mã",
|
||||
"doubleTapToViewHiddenCode": "Bạn có thể nhấn đúp vào một mục để xem mã",
|
||||
"focusOnSearchBar": "Mở tìm kiếm khi khởi động ứng dụng",
|
||||
"confirmUpdatingkey": "Bạn có chắc chắn muốn cập nhật khóa bí mật không?",
|
||||
"minimizeAppOnCopy": "Thu nhỏ khi sao chép",
|
||||
"editCodeAuthMessage": "Xác minh để chỉnh sửa mã",
|
||||
"deleteCodeAuthMessage": "Xác minh để xóa mã",
|
||||
"showQRAuthMessage": "Xác minh để hiển thị mã QR"
|
||||
"showQRAuthMessage": "Xác minh để hiển thị mã QR",
|
||||
"confirmAccountDeleteTitle": "Xác nhận xóa tài khoản",
|
||||
"confirmAccountDeleteMessage": "Tài khoản này được liên kết với các ứng dụng ente khác, nếu bạn sử dụng bất kỳ ứng dụng nào.\n\nDữ liệu đã tải lên của bạn, trên tất cả các ứng dụng, sẽ bị lên lịch xóa và tài khoản của bạn sẽ bị xóa vĩnh viễn.",
|
||||
"androidBiometricHint": "Xác định danh tính",
|
||||
"@androidBiometricHint": {
|
||||
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricNotRecognized": "Không nhận dạng được. Vui lòng thử lại.",
|
||||
"@androidBiometricNotRecognized": {
|
||||
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricSuccess": "Thành công",
|
||||
"@androidBiometricSuccess": {
|
||||
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidCancelButton": "Hủy",
|
||||
"@androidCancelButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
|
||||
},
|
||||
"androidSignInTitle": "Yêu cầu xác thực",
|
||||
"@androidSignInTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidBiometricRequiredTitle": "Yêu cầu sinh trắc học",
|
||||
"@androidBiometricRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsRequiredTitle": "Yêu cầu thông tin xác thực thiết bị",
|
||||
"@androidDeviceCredentialsRequiredTitle": {
|
||||
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
|
||||
},
|
||||
"androidDeviceCredentialsSetupDescription": "Yêu cầu thông tin xác thực thiết bị",
|
||||
"@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": "Chuyển đến cài đặt",
|
||||
"@goToSettings": {
|
||||
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
|
||||
},
|
||||
"androidGoToSettingsDescription": "Xác thực sinh trắc học chưa được thiết lập trên thiết bị của bạn. Đi tới 'Cài đặt > Bảo mật' để thêm xác thực sinh trắc học.",
|
||||
"@androidGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
|
||||
},
|
||||
"iOSLockOut": "Xác thực sinh trắc học bị vô hiệu hóa. Vui lòng khóa và mở khóa màn hình của bạn để kích hoạt nó.",
|
||||
"@iOSLockOut": {
|
||||
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSGoToSettingsDescription": "Xác thực sinh trắc học chưa được thiết lập trên thiết bị của bạn. Vui lòng bật Touch ID hoặc Face ID trên điện thoại của bạn.",
|
||||
"@iOSGoToSettingsDescription": {
|
||||
"description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
|
||||
},
|
||||
"iOSOkButton": "Đồng ý",
|
||||
"@iOSOkButton": {
|
||||
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
|
||||
},
|
||||
"noInternetConnection": "Không có kết nối Internet",
|
||||
"pleaseCheckYourInternetConnectionAndTryAgain": "Vui lòng kiểm tra kết nối internet của bạn và thử lại.",
|
||||
"signOutFromOtherDevices": "Đăng xuất khỏi các thiết bị khác",
|
||||
"signOutOtherBody": "Nếu bạn cho rằng ai đó có thể biết mật khẩu của mình, bạn có thể buộc đăng xuất tất cả các thiết bị khác đang sử dụng tài khoản của mình.",
|
||||
"signOutOtherDevices": "Đăng xuất khỏi các thiết bị khác",
|
||||
"doNotSignOut": "Không được đăng xuất",
|
||||
"hearUsWhereTitle": "Bạn biết đến Ente bằng cách nào? (không bắt buộc)",
|
||||
"hearUsExplanation": "Chúng tôi không theo dõi lượt cài đặt ứng dụng. Sẽ rất hữu ích nếu bạn cho chúng tôi biết nơi bạn tìm thấy chúng tôi!"
|
||||
}
|
||||
@@ -401,5 +401,7 @@
|
||||
"signOutFromOtherDevices": "从其他设备退出登录",
|
||||
"signOutOtherBody": "如果你认为有人可能知道你的密码,你可以强制所有使用你账户的其他设备退出登录。",
|
||||
"signOutOtherDevices": "登出其他设备",
|
||||
"doNotSignOut": "不要退登"
|
||||
"doNotSignOut": "不要退登",
|
||||
"hearUsWhereTitle": "您是如何知道Ente的? (可选的)",
|
||||
"hearUsExplanation": "我们不跟踪应用程序安装情况。如果您告诉我们您是在哪里找到我们的,将会有所帮助!"
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import "package:flutter/material.dart";
|
||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:privacy_screen/privacy_screen.dart';
|
||||
|
||||
final _logger = Logger("main");
|
||||
|
||||
@@ -31,6 +32,22 @@ void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final savedThemeMode = await AdaptiveTheme.getThemeMode();
|
||||
await _runInForeground(savedThemeMode);
|
||||
await PrivacyScreen.instance.enable(
|
||||
iosOptions: const PrivacyIosOptions(
|
||||
enablePrivacy: true,
|
||||
privacyImageName: "LaunchImage",
|
||||
lockTrigger: IosLockTrigger.didEnterBackground,
|
||||
),
|
||||
androidOptions: const PrivacyAndroidOptions(
|
||||
enableSecure: true,
|
||||
),
|
||||
backgroundColor: savedThemeMode == AdaptiveThemeMode.dark
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
blurEffect: savedThemeMode == AdaptiveThemeMode.dark
|
||||
? PrivacyBlurEffect.dark
|
||||
: PrivacyBlurEffect.extraLight,
|
||||
);
|
||||
FlutterDisplayMode.setHighRefreshRate();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,72 +18,81 @@ class HomeEmptyStateWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(height: 800, width: 450),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/wallet-front-gradient.png",
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
Text(
|
||||
l10n.setupFirstAccount,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
const SizedBox(height: 64),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onScanTap,
|
||||
child: Text(l10n.importScanQrCode),
|
||||
return SingleChildScrollView(
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints.tightFor(height: 800, width: 450),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 40),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
"assets/wallet-front-gradient.png",
|
||||
width: 200,
|
||||
height: 200,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onManuallySetupTap,
|
||||
child: Text(l10n.importEnterSetupKey),
|
||||
Text(
|
||||
l10n.setupFirstAccount,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 54),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
routeToPage(context, ImportCodePage());
|
||||
},
|
||||
child: Text(
|
||||
l10n.importCodes,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context).bodyFaint.copyWith(decoration: TextDecoration.underline),
|
||||
),),
|
||||
const SizedBox(height: 18),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
barrierColor: Colors.black87,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const FAQQuestionsWidget();
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
l10n.faq,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context).bodyFaint.copyWith(decoration: TextDecoration.underline),
|
||||
),),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 64),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onScanTap,
|
||||
child: Text(l10n.importScanQrCode),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: OutlinedButton(
|
||||
onPressed: onManuallySetupTap,
|
||||
child: Text(l10n.importEnterSetupKey),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 54),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
routeToPage(context, ImportCodePage());
|
||||
},
|
||||
child: Text(
|
||||
l10n.importCodes,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context)
|
||||
.bodyFaint
|
||||
.copyWith(decoration: TextDecoration.underline),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showModalBottomSheet<void>(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.background,
|
||||
barrierColor: Colors.black87,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const FAQQuestionsWidget();
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
l10n.faq,
|
||||
textAlign: TextAlign.center,
|
||||
style: getEnteTextTheme(context)
|
||||
.bodyFaint
|
||||
.copyWith(decoration: TextDecoration.underline),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -80,18 +80,25 @@ Future<int?> _processBitwardenExportFile(
|
||||
List<dynamic> jsonArray = data['items'];
|
||||
final parsedCodes = [];
|
||||
for (var item in jsonArray) {
|
||||
if (item['login']['totp'] != null) {
|
||||
var issuer = item['name'];
|
||||
var account = item['login']['username'];
|
||||
var secret = item['login']['totp'];
|
||||
if (item['login'] != null && item['login']['totp'] != null) {
|
||||
var totp = item['login']['totp'];
|
||||
|
||||
parsedCodes.add(
|
||||
Code.fromAccountAndSecret(
|
||||
Code code;
|
||||
|
||||
if (totp.contains("otpauth://")) {
|
||||
code = Code.fromRawData(totp);
|
||||
} else {
|
||||
var issuer = item['name'];
|
||||
var account = item['login']['username'];
|
||||
|
||||
code = Code.fromAccountAndSecret(
|
||||
account,
|
||||
issuer,
|
||||
secret,
|
||||
),
|
||||
);
|
||||
totp,
|
||||
);
|
||||
}
|
||||
|
||||
parsedCodes.add(code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -14,6 +15,8 @@ class IconUtils {
|
||||
// Map of icon-title to the color code in HEX
|
||||
final Map<String, String> _simpleIcons = {};
|
||||
final Map<String, CustomIconData> _customIcons = {};
|
||||
// Map of icon-color to its luminance
|
||||
final Map<Color, double> _colorLuminance = {};
|
||||
|
||||
Future<void> init() async {
|
||||
await _loadJson();
|
||||
@@ -31,6 +34,7 @@ class IconUtils {
|
||||
title,
|
||||
_customIcons[title]!.color,
|
||||
width,
|
||||
context,
|
||||
);
|
||||
} else if (_simpleIcons.containsKey(title)) {
|
||||
return _getSVGIcon(
|
||||
@@ -38,6 +42,7 @@ class IconUtils {
|
||||
title,
|
||||
_simpleIcons[title],
|
||||
width,
|
||||
context,
|
||||
);
|
||||
} else if (title.isNotEmpty) {
|
||||
bool showLargeIcon = width > 24;
|
||||
@@ -63,33 +68,64 @@ class IconUtils {
|
||||
String title,
|
||||
String? color,
|
||||
double width,
|
||||
BuildContext context,
|
||||
) {
|
||||
final iconColor = _getAdaptiveColor(color, context);
|
||||
return SvgPicture.asset(
|
||||
path,
|
||||
width: width,
|
||||
semanticsLabel: title,
|
||||
colorFilter: color != null
|
||||
colorFilter: iconColor != null
|
||||
? ColorFilter.mode(
|
||||
Color(int.parse("0xFF" + color)),
|
||||
iconColor,
|
||||
BlendMode.srcIn,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Color? _getAdaptiveColor(String? hexColor, BuildContext context) {
|
||||
if (hexColor == null) return null;
|
||||
final theme = Theme.of(context).brightness;
|
||||
final color = Color(int.parse("0xFF" + hexColor));
|
||||
// Color is close to neutral-grey and it's too light or dark for theme
|
||||
if (_isCloseToNeutralGrey(color) &&
|
||||
((theme == Brightness.light && _getColorLuminance(color) > 0.70) ||
|
||||
(theme == Brightness.dark && _getColorLuminance(color) < 0.05))) {
|
||||
return Theme.of(context).colorScheme.iconColor;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
double _getColorLuminance(Color color) {
|
||||
return _colorLuminance.putIfAbsent(color, () => color.computeLuminance());
|
||||
}
|
||||
|
||||
bool _isCloseToNeutralGrey(Color color, {double tolerance = 3}) {
|
||||
return (color.red - color.green).abs() <= tolerance &&
|
||||
(color.green - color.blue).abs() <= tolerance &&
|
||||
(color.blue - color.red).abs() <= tolerance;
|
||||
}
|
||||
|
||||
Future<void> _loadJson() async {
|
||||
try {
|
||||
final simpleIconData = await rootBundle
|
||||
.loadString('assets/simple-icons/_data/simple-icons.json');
|
||||
final simpleIcons = json.decode(simpleIconData);
|
||||
for (final icon in simpleIcons["icons"]) {
|
||||
_simpleIcons[icon["title"].toString().toLowerCase()] = icon["hex"];
|
||||
_simpleIcons[icon["title"]
|
||||
.toString()
|
||||
.replaceAll(' ', '')
|
||||
.toLowerCase()] = icon["hex"];
|
||||
}
|
||||
final customIconData = await rootBundle
|
||||
.loadString('assets/custom-icons/_data/custom-icons.json');
|
||||
final customIcons = json.decode(customIconData);
|
||||
for (final icon in customIcons["icons"]) {
|
||||
_customIcons[icon["title"].toString().toLowerCase()] = CustomIconData(
|
||||
_customIcons[icon["title"]
|
||||
.toString()
|
||||
.replaceAll(' ', '')
|
||||
.toLowerCase()] = CustomIconData(
|
||||
icon["slug"],
|
||||
icon["hex"],
|
||||
);
|
||||
@@ -108,7 +144,7 @@ class IconUtils {
|
||||
}
|
||||
|
||||
String _getProviderTitle(String provider) {
|
||||
return provider.split(RegExp(r'[.(]'))[0].trim().toLowerCase();
|
||||
return provider.split(RegExp(r'[.(]'))[0].replaceAll(' ', '').toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
migration-guides/decrypt/bin/ente-decrypt-darwin-amd64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-darwin-arm64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-386
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-amd64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-arm
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-linux-arm64
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-windows-386.exe
Executable file
BIN
migration-guides/decrypt/bin/ente-decrypt-windows-amd64.exe
Executable file
@@ -1,13 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/jamesruan/sodium"
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
@@ -48,23 +45,38 @@ func deriveArgonKey(password, salt string, memLimit, opsLimit int) ([]byte, erro
|
||||
// Returns:
|
||||
// - A byte slice representing the decrypted data.
|
||||
// - An error object, which is nil if no error occurs.
|
||||
func decryptChaCha20poly1305(data []byte, key []byte, nonce []byte) ([]byte, error) {
|
||||
reader := bytes.NewReader(data)
|
||||
header := sodium.SecretStreamXCPHeader{Bytes: nonce}
|
||||
decoder, err := sodium.MakeSecretStreamXCPDecoder(
|
||||
sodium.SecretStreamXCPKey{Bytes: key},
|
||||
reader,
|
||||
header)
|
||||
// func decryptChaCha20poly13052(data []byte, key []byte, nonce []byte) ([]byte, error) {
|
||||
// reader := bytes.NewReader(data)
|
||||
// header := sodium.SecretStreamXCPHeader{Bytes: nonce}
|
||||
// decoder, err := sodium.MakeSecretStreamXCPDecoder(
|
||||
// sodium.SecretStreamXCPKey{Bytes: key},
|
||||
// reader,
|
||||
// header)
|
||||
// if err != nil {
|
||||
// log.Println("Failed to make secret stream decoder", err)
|
||||
// return nil, err
|
||||
// }
|
||||
// // Buffer to store the decrypted data
|
||||
// decryptedData := make([]byte, len(data))
|
||||
// n, err := decoder.Read(decryptedData)
|
||||
// if err != nil && err != io.EOF {
|
||||
// log.Println("Failed to read from decoder", err)
|
||||
// return nil, err
|
||||
// }
|
||||
// return decryptedData[:n], nil
|
||||
// }
|
||||
|
||||
func decryptChaCha20poly13052(data []byte, key []byte, nonce []byte) ([]byte, error) {
|
||||
decryptor, err := NewDecryptor(key, nonce)
|
||||
if err != nil {
|
||||
log.Println("Failed to make secret stream decoder", err)
|
||||
return nil, err
|
||||
}
|
||||
// Buffer to store the decrypted data
|
||||
decryptedData := make([]byte, len(data))
|
||||
n, err := decoder.Read(decryptedData)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Println("Failed to read from decoder", err)
|
||||
decoded, tag, err := decryptor.Pull(data)
|
||||
if tag != TagFinal {
|
||||
return nil, errors.New("invalid tag")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decryptedData[:n], nil
|
||||
return decoded, nil
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestDecryptChaCha20poly1305(t *testing.T) {
|
||||
t.Fatalf("Failed to decode cipher nonce: %v", err)
|
||||
}
|
||||
|
||||
decryptedText, err := decryptChaCha20poly1305(decodedCipherText, derivedKey, decodedCipherNonce)
|
||||
decryptedText, err := decryptChaCha20poly13052(decodedCipherText, derivedKey, decodedCipherNonce)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to decrypt: %v", err)
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
decryptedData, err := decryptChaCha20poly1305(encryptedData, key, nonce)
|
||||
decryptedData, err := decryptChaCha20poly13052(encryptedData, key, nonce)
|
||||
if err != nil {
|
||||
fmt.Println("Error decrypting data:", err)
|
||||
return
|
||||
|
||||
@@ -2,9 +2,6 @@ module decrypt
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/jamesruan/sodium v1.0.14
|
||||
golang.org/x/crypto v0.11.0
|
||||
)
|
||||
require golang.org/x/crypto v0.11.0
|
||||
|
||||
require golang.org/x/sys v0.10.0 // indirect
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
github.com/jamesruan/sodium v1.0.14 h1:JfOHobip/lUWouxHV3PwYwu3gsLewPrDrZXO3HuBzUU=
|
||||
github.com/jamesruan/sodium v1.0.14/go.mod h1:GK2+LACf7kuVQ9k7Irk0MB2B65j5rVqkz+9ylGIggZk=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
|
||||
43
migration-guides/decrypt/release.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Create a "bin" directory if it doesn't exist
|
||||
mkdir -p bin
|
||||
|
||||
# List of target operating systems
|
||||
OS_TARGETS=("windows" "linux" "darwin")
|
||||
|
||||
# Corresponding architectures for each OS
|
||||
ARCH_TARGETS=("386 amd64" "386 amd64 arm arm64" "amd64 arm64")
|
||||
|
||||
# Loop through each OS target
|
||||
for index in "${!OS_TARGETS[@]}"
|
||||
do
|
||||
OS=${OS_TARGETS[$index]}
|
||||
for ARCH in ${ARCH_TARGETS[$index]}
|
||||
do
|
||||
# Set the GOOS environment variable for the current target OS
|
||||
export GOOS="$OS"
|
||||
export GOARCH="$ARCH"
|
||||
|
||||
# Set the output binary name to "ente-decrypt" for the current OS and architecture
|
||||
BINARY_NAME="ente-decrypt-$OS-$ARCH"
|
||||
|
||||
# Add .exe extension for Windows
|
||||
if [ "$OS" == "windows" ]; then
|
||||
BINARY_NAME="ente-decrypt-$OS-$ARCH.exe"
|
||||
fi
|
||||
|
||||
# Build the binary and place it in the "bin" directory
|
||||
go build -o "bin/$BINARY_NAME" decrypt.go crypt.go stream.go
|
||||
|
||||
# Print a message indicating the build is complete for the current OS and architecture
|
||||
echo "Built for $OS ($ARCH) as bin/$BINARY_NAME"
|
||||
done
|
||||
done
|
||||
|
||||
# Clean up any environment variables
|
||||
unset GOOS
|
||||
unset GOARCH
|
||||
|
||||
# Print a message indicating the build process is complete
|
||||
echo "Build process completed for all platforms and architectures. Binaries are in the 'bin' directory."
|
||||
409
migration-guides/decrypt/stream.go
Normal file
@@ -0,0 +1,409 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/chacha20"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
)
|
||||
|
||||
// public constants
|
||||
const (
|
||||
//TagMessage the most common tag, that doesn't add any information about the nature of the message.
|
||||
TagMessage = 0
|
||||
// TagPush indicates that the message marks the end of a set of messages,
|
||||
// but not the end of the stream. For example, a huge JSON string sent as multiple chunks can use this tag to indicate to the application that the string is complete and that it can be decoded. But the stream itself is not closed, and more data may follow.
|
||||
TagPush = 0x01
|
||||
// TagRekey "forget" the key used to encrypt this message and the previous ones, and derive a new secret key.
|
||||
TagRekey = 0x02
|
||||
// TagFinal indicates that the message marks the end of the stream, and erases the secret key used to encrypt the previous sequence.
|
||||
TagFinal = TagPush | TagRekey
|
||||
|
||||
StreamKeyBytes = chacha20poly1305.KeySize
|
||||
StreamHeaderBytes = chacha20poly1305.NonceSizeX
|
||||
// XChaCha20Poly1305IetfABYTES links to crypto_secretstream_xchacha20poly1305_ABYTES
|
||||
XChaCha20Poly1305IetfABYTES = 16 + 1
|
||||
)
|
||||
|
||||
const cryptoCoreHchacha20InputBytes = 16
|
||||
|
||||
/* const crypto_secretstream_xchacha20poly1305_INONCEBYTES = 8 */
|
||||
const cryptoSecretStreamXchacha20poly1305Counterbytes = 4
|
||||
|
||||
var pad0 [16]byte
|
||||
|
||||
var invalidKey = errors.New("invalid key")
|
||||
var invalidInput = errors.New("invalid input")
|
||||
var cryptoFailure = errors.New("crypto failed")
|
||||
|
||||
func memZero(b []byte) {
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func xorBuf(out, in []byte) {
|
||||
for i := range out {
|
||||
out[i] ^= in[i]
|
||||
}
|
||||
}
|
||||
|
||||
func bufInc(n []byte) {
|
||||
c := 1
|
||||
|
||||
for i := range n {
|
||||
c += int(n[i])
|
||||
n[i] = byte(c)
|
||||
c >>= 8
|
||||
}
|
||||
}
|
||||
|
||||
// crypto_secretstream_xchacha20poly1305_state
|
||||
type streamState struct {
|
||||
k [StreamKeyBytes]byte
|
||||
nonce [chacha20poly1305.NonceSize]byte
|
||||
pad [8]byte
|
||||
}
|
||||
|
||||
func (s *streamState) reset() {
|
||||
for i := range s.nonce {
|
||||
s.nonce[i] = 0
|
||||
}
|
||||
s.nonce[0] = 1
|
||||
}
|
||||
|
||||
type Encryptor interface {
|
||||
Push(m []byte, tag byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type Decryptor interface {
|
||||
Pull(m []byte) ([]byte, byte, error)
|
||||
}
|
||||
|
||||
type encryptor struct {
|
||||
streamState
|
||||
}
|
||||
|
||||
type decryptor struct {
|
||||
streamState
|
||||
}
|
||||
|
||||
func NewStreamKey() []byte {
|
||||
k := make([]byte, chacha20poly1305.KeySize)
|
||||
_, _ = rand.Read(k)
|
||||
return k
|
||||
}
|
||||
|
||||
func NewEncryptor(key []byte) (Encryptor, []byte, error) {
|
||||
if len(key) != StreamKeyBytes {
|
||||
return nil, nil, invalidKey
|
||||
}
|
||||
|
||||
header := make([]byte, StreamHeaderBytes)
|
||||
_, _ = rand.Read(header)
|
||||
|
||||
stream := &encryptor{}
|
||||
|
||||
k, err := chacha20.HChaCha20(key[:], header[:16])
|
||||
if err != nil {
|
||||
//fmt.Printf("error: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
copy(stream.k[:], k)
|
||||
stream.reset()
|
||||
|
||||
for i := range stream.pad {
|
||||
stream.pad[i] = 0
|
||||
}
|
||||
|
||||
for i, b := range header[cryptoCoreHchacha20InputBytes:] {
|
||||
stream.nonce[i+cryptoSecretStreamXchacha20poly1305Counterbytes] = b
|
||||
}
|
||||
// fmt.Printf("stream: %+v\n", stream.streamState)
|
||||
|
||||
return stream, header, nil
|
||||
}
|
||||
|
||||
func (s *encryptor) Push(plain []byte, tag byte) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
//crypto_onetimeauth_poly1305_state poly1305_state;
|
||||
var poly *poly1305.MAC
|
||||
|
||||
//unsigned char block[64U];
|
||||
var block [64]byte
|
||||
|
||||
//unsigned char slen[8U];
|
||||
var slen [8]byte
|
||||
|
||||
//unsigned char *c;
|
||||
//unsigned char *mac;
|
||||
//
|
||||
//if (outlen_p != NULL) {
|
||||
//*outlen_p = 0U;
|
||||
//}
|
||||
|
||||
mlen := len(plain)
|
||||
//if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
//sodium_misuse();
|
||||
//}
|
||||
|
||||
out := make([]byte, mlen+XChaCha20Poly1305IetfABYTES)
|
||||
|
||||
chacha, err := chacha20.NewUnauthenticatedCipher(s.k[:], s.nonce[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
|
||||
//crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
var poly_init [32]byte
|
||||
copy(poly_init[:], block[:])
|
||||
poly = poly1305.New(&poly_init)
|
||||
|
||||
// TODO add support for add data
|
||||
//sodium_memzero(block, sizeof block);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
//(0x10 - adlen) & 0xf);
|
||||
|
||||
//memset(block, 0, sizeof block);
|
||||
//block[0] = tag;
|
||||
memZero(block[:])
|
||||
block[0] = tag
|
||||
|
||||
//
|
||||
//crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, state->nonce, 1U, state->k);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
//out[0] = block[0];
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
_, _ = poly.Write(block[:])
|
||||
out[0] = block[0]
|
||||
|
||||
//
|
||||
//c = out + (sizeof tag);
|
||||
c := out[1:]
|
||||
//crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
//crypto_onetimeauth_poly1305_update (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
chacha.XORKeyStream(c, plain)
|
||||
_, _ = poly.Write(c[:mlen])
|
||||
padlen := (0x10 - len(block) + mlen) & 0xf
|
||||
_, _ = poly.Write(pad0[:padlen])
|
||||
|
||||
//
|
||||
//STORE64_LE(slen, (uint64_t) adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(0))
|
||||
_, _ = poly.Write(slen[:])
|
||||
|
||||
//STORE64_LE(slen, (sizeof block) + mlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(len(block)+mlen))
|
||||
_, _ = poly.Write(slen[:])
|
||||
|
||||
//
|
||||
//mac = c + mlen;
|
||||
//crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
mac := c[mlen:]
|
||||
copy(mac, poly.Sum(nil))
|
||||
//sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
//
|
||||
|
||||
//XOR_BUF(STATE_INONCE(state), mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
//sodium_increment(STATE_COUNTER(state), crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
xorBuf(s.nonce[cryptoSecretStreamXchacha20poly1305Counterbytes:], mac)
|
||||
bufInc(s.nonce[:cryptoSecretStreamXchacha20poly1305Counterbytes])
|
||||
|
||||
// TODO
|
||||
//if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
//sodium_is_zero(STATE_COUNTER(state),
|
||||
//crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
//crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
//}
|
||||
|
||||
//if (outlen_p != NULL) {
|
||||
//*outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
|
||||
//}
|
||||
|
||||
//return 0;
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func NewDecryptor(key, header []byte) (Decryptor, error) {
|
||||
stream := &decryptor{}
|
||||
|
||||
//crypto_core_hchacha20(state->k, in, k, NULL);
|
||||
k, err := chacha20.HChaCha20(key, header[:16])
|
||||
if err != nil {
|
||||
fmt.Printf("error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
copy(stream.k[:], k)
|
||||
|
||||
//_crypto_secretstream_xchacha20poly1305_counter_reset(state);
|
||||
stream.reset()
|
||||
|
||||
//memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
|
||||
// crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
copy(stream.nonce[cryptoSecretStreamXchacha20poly1305Counterbytes:],
|
||||
header[cryptoCoreHchacha20InputBytes:])
|
||||
|
||||
//memset(state->_pad, 0, sizeof state->_pad);
|
||||
copy(stream.pad[:], pad0[:])
|
||||
|
||||
//fmt.Printf("decryptor: %+v\n", stream.streamState)
|
||||
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
func (s *decryptor) Pull(cipher []byte) ([]byte, byte, error) {
|
||||
cipherLen := len(cipher)
|
||||
|
||||
//crypto_onetimeauth_poly1305_state poly1305_state;
|
||||
var poly1305State [32]byte
|
||||
|
||||
//unsigned char block[64U];
|
||||
var block [64]byte
|
||||
//unsigned char slen[8U];
|
||||
var slen [8]byte
|
||||
|
||||
//unsigned char mac[crypto_onetimeauth_poly1305_BYTES];
|
||||
//const unsigned char *c;
|
||||
//const unsigned char *stored_mac;
|
||||
//unsigned long long mlen; // length of the returned message
|
||||
//unsigned char tag; // for the return value
|
||||
//
|
||||
//if (mlen_p != NULL) {
|
||||
//*mlen_p = 0U;
|
||||
//}
|
||||
//if (tag_p != NULL) {
|
||||
//*tag_p = 0xff;
|
||||
//}
|
||||
|
||||
/*
|
||||
if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) {
|
||||
return -1;
|
||||
}
|
||||
mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||
*/
|
||||
if cipherLen < XChaCha20Poly1305IetfABYTES {
|
||||
return nil, 0, invalidInput
|
||||
}
|
||||
mlen := cipherLen - XChaCha20Poly1305IetfABYTES
|
||||
|
||||
//if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
//sodium_misuse();
|
||||
//}
|
||||
|
||||
//crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
chacha, err := chacha20.NewUnauthenticatedCipher(s.k[:], s.nonce[:])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
|
||||
//crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
|
||||
copy(poly1305State[:], block[:])
|
||||
poly := poly1305.New(&poly1305State)
|
||||
|
||||
// TODO
|
||||
//sodium_memzero(block, sizeof block);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
//(0x10 - adlen) & 0xf);
|
||||
//
|
||||
|
||||
//memset(block, 0, sizeof block);
|
||||
//block[0] = in[0];
|
||||
//crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, state->nonce, 1U, state->k);
|
||||
memZero(block[:])
|
||||
block[0] = cipher[0]
|
||||
chacha.XORKeyStream(block[:], block[:])
|
||||
|
||||
//tag = block[0];
|
||||
//block[0] = in[0];
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
tag := block[0]
|
||||
block[0] = cipher[0]
|
||||
if _, err = poly.Write(block[:]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//c = in + (sizeof tag);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
//crypto_onetimeauth_poly1305_update (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
c := cipher[1:]
|
||||
if _, err = poly.Write(c[:mlen]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
padLen := (0x10 - len(block) + mlen) & 0xf
|
||||
if _, err = poly.Write(pad0[:padLen]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//
|
||||
//STORE64_LE(slen, (uint64_t) adlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(0))
|
||||
if _, err = poly.Write(slen[:]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//STORE64_LE(slen, (sizeof block) + mlen);
|
||||
//crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
binary.LittleEndian.PutUint64(slen[:], uint64(len(block)+mlen))
|
||||
if _, err = poly.Write(slen[:]); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//
|
||||
//crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
//sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
|
||||
mac := poly.Sum(nil)
|
||||
memZero(poly1305State[:])
|
||||
|
||||
//stored_mac = c + mlen;
|
||||
//if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
|
||||
//sodium_memzero(mac, sizeof mac);
|
||||
//return -1;
|
||||
//}
|
||||
storedMac := c[mlen:]
|
||||
if !bytes.Equal(mac, storedMac) {
|
||||
memZero(mac)
|
||||
return nil, 0, cryptoFailure
|
||||
}
|
||||
|
||||
//crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
|
||||
//XOR_BUF(STATE_INONCE(state), mac, crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
//sodium_increment(STATE_COUNTER(state), crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
m := make([]byte, mlen)
|
||||
chacha.XORKeyStream(m, c[:mlen])
|
||||
|
||||
xorBuf(s.nonce[cryptoSecretStreamXchacha20poly1305Counterbytes:], mac)
|
||||
bufInc(s.nonce[:cryptoSecretStreamXchacha20poly1305Counterbytes])
|
||||
|
||||
// TODO
|
||||
//if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
//sodium_is_zero(STATE_COUNTER(state),
|
||||
//crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
//crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
//}
|
||||
|
||||
//if (mlen_p != NULL) {
|
||||
//*mlen_p = mlen;
|
||||
//}
|
||||
//if (tag_p != NULL) {
|
||||
//*tag_p = tag;
|
||||
//}
|
||||
//return 0;
|
||||
return m, tag, nil
|
||||
}
|
||||
@@ -56,7 +56,7 @@ For encryption, we are using `XChaCha20-Poly1305` algorithm.
|
||||
* **ente Authenticator app**: You can directly import the codes in the ente Authenticator app.
|
||||
> Settings -> Data -> Import Codes -> ente Encrypted export.
|
||||
|
||||
* **Decryption Tool** : You can download the prebuilt [decryption tool](decrypt/decrypt) (or build it from [source](decrypt)) and run the following command.
|
||||
* **Decryption Tool** : You can download the prebuilt [decryption tool](decrypt/bin/) (or build it from [source](decrypt)) and run the following command.
|
||||
|
||||
```
|
||||
./decrypt <export_file> <password> <output_file>
|
||||
|
||||
@@ -1047,6 +1047,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
privacy_screen:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: privacy_screen
|
||||
sha256: b80297d2726d96e8a8341149e81a415302755f02d3af7c05c820d9e191bbfbee
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.6"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 2.0.26+226
|
||||
version: 2.0.30+230
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -67,6 +67,7 @@ dependencies:
|
||||
path_provider: ^2.0.11
|
||||
pinput: ^1.2.2
|
||||
pointycastle: ^3.7.3
|
||||
privacy_screen: ^0.0.6
|
||||
protobuf: ^3.0.0
|
||||
qr_code_scanner: ^1.0.1
|
||||
qr_flutter: 4.0.0
|
||||
|
||||