Compare commits

...

229 Commits

Author SHA1 Message Date
Vishnu Mohandas
974c34a569 Ignore spaces within provider names (#395)
Fixes #393.

Tested with an entry within Simple Icons ("Deutsche Bahn") and an entry
within our Custom Icons ("Anycoin Direct").
2023-12-18 21:37:39 +05:30
github-actions[bot]
4dc31c3e60 New Translations (#397)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-12-18 21:35:53 +05:30
github-actions[bot]
fa60a22443 New Translations (#396)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-12-18 10:34:15 +05:30
Lukas Bestle
cf55c48b4c Add several custom icons (#394)
## Description

Added custom icons that don't meet the requirements of Simple Icons
(especially because they are full-color).

The Airtable and Discourse icons are an upgrade to the single-color
icons in Simple Icons, the others are not available yet at all.

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [x] 🖼️ New icon
- [ ]  New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ]  Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] 🧹 Code refactor
- [ ]  Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore
2023-12-17 17:17:32 +05:30
github-actions[bot]
56290b1df6 New Translations (#391)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-12-15 14:09:16 +05:30
github-actions[bot]
8d468dbc91 New Translations (#389)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-12-07 08:03:24 +05:30
Muhammed Ayimen Abdul Latheef
1a654fe748 Added: When the app is in the background, hided te contents of the app (#387)
<!--
  Thanks for contributing!

Provide a description of your changes below and a general summary in the
title

Please look at the following checklist to ensure that your PR can be
accepted quickly:
-->

## Description

Added: Hide the contents of the app, when is it in the background - Both
android and ios

In android, it shows a blank white/black background, when in background

In iOS, it shows the launch icon, when in background


![photo_2023-12-06_12-53-02](https://github.com/ente-io/auth/assets/54765537/4f787e6a-984c-4eae-9028-303a32009838)

Android Physical Device


![photo_2023-12-06_12-52-55](https://github.com/ente-io/auth/assets/54765537/b8802cf5-0db0-473e-8be8-8cf3bf7b29a5)

Android stimulator

Also, compared the bitwarden apps in android, the flow is same

iOS Device: Need to verify 
@ua741 @vishnukvmd Could you run on iOS devices and verify it?

Closes #47 

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [ ] 🖼️ New icon
- [x]  New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ]  Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] 🧹 Code refactor
- [ ]  Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore
2023-12-06 13:50:36 +05:30
github-actions[bot]
1606b74b40 New Translations (#388) 2023-12-06 09:47:32 +05:30
Vishnu Mohandas
8d82851741 Update CONTRIBUTION.md (#385) 2023-12-04 10:48:51 +05:30
github-actions[bot]
a6ca5697d9 New Translations (#381)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-12-04 08:12:11 +05:30
github-actions[bot]
e01ba961a6 New Translations (#378)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-27 22:43:46 +05:30
Neeraj Gupta
a256bc9922 EmailVerification: Improve copy for warning (#377) 2023-11-27 22:02:18 +05:30
Neeraj Gupta
77632b3241 Bump version 2.0.26+226 2023-11-27 18:39:22 +05:30
Neeraj Gupta
d02e02a326 Sign up: Add field for 'hear us from' info (#376) 2023-11-27 18:06:49 +05:30
github-actions[bot]
7fe314a16a New Translations (#375)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-27 18:04:23 +05:30
green
504fa939d2 Add CLI tool + disclaimer to Authy guide (#373)
<!--
  Thanks for contributing!

Provide a description of your changes below and a general summary in the
title

Please look at the following checklist to ensure that your PR can be
accepted quickly:
-->

## Description
Adds a hyperlink to Neeraj's CLI tool shown in ente Discord, as well as
a disclaimer to check all accounts have been imported before deleting
Authy data
<!--- Describe your changes in detail -->

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [ ] 🖼️ New icon
- [ ]  New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ]  Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] 🧹 Code refactor
- [ ]  Build configuration change
- [x] 📝 Documentation
- [ ] 🗑️ Chore
2023-11-27 08:33:49 +05:30
Neeraj Gupta
17f5a7996a Change Password: Confirm before signing out from other devices (#374) 2023-11-26 16:27:25 +05:30
Neeraj Gupta
cf6b4f5423 Enable import for 2fas v4 (#372) 2023-11-26 14:19:33 +05:30
github-actions[bot]
ca46765760 New Translations (#371)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-26 13:40:47 +05:30
Neeraj Gupta
4de3287f55 Support importing 2FAS export (v3) (#370)
Tested locally.

Planning to extract the strings separately while merging common strings
from other import sections.
2023-11-26 13:38:47 +05:30
Neeraj Gupta
cdc27e061b Fix: Add missing await (#368) 2023-11-24 22:07:04 +05:30
Tanguy
78b3d239eb Add Proxmox logo (#366)
<!--
  Thanks for contributing!

Provide a description of your changes below and a general summary in the
title

Please look at the following checklist to ensure that your PR can be
accepted quickly:
-->

New logo + refractor

<!--- Describe your changes in detail -->

Add Proxmox logo. Remove test icon. Refractor X icon data with altNames.

SVGs with mix-blend-mode appear to be glitchy in emulators but not on
real devices
(https://github.com/dnfield/flutter_svg/issues/922#issuecomment-1552104687).
By the way, SVGs using mix-blend-mode get pixelated. This is probably
because of `flutter_svg` library
(https://github.com/dnfield/flutter_svg/issues/985). I didn't go into
any depth, I didn't feel like digging into the code.

<!--- Put an `x` in all the boxes that apply: -->

- [x] 🖼️ New icon
- [ ]  New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ]  Breaking change (fix or feature that would cause existing
functionality to change)
- [x] 🧹 Code refactor
- [ ]  Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore
2023-11-24 10:42:28 +05:30
github-actions[bot]
005d3b0eca New Translations (#364)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-23 07:20:03 +05:30
github-actions[bot]
23ba69c6a6 New Translations (#363)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-21 10:35:26 +05:30
Neeraj Gupta
d644ee97e1 Bump version 2.0.22+222 2023-11-20 18:15:10 +05:30
Neeraj Gupta
0afd0d63b3 Show hint that double tapping on hidden code makes it visible (#362)
Related to #331
2023-11-20 18:14:13 +05:30
Neeraj Gupta
f04d9b94d9 Add device auth for sign in to backup action (#361)
Related to #337
2023-11-20 18:08:41 +05:30
github-actions[bot]
8cd4ec30af New Translations (#360)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-20 17:35:33 +05:30
Neeraj Gupta
4215810cf8 Add fix for loginViaSRP (#359)
Port fixes from photos-app
2023-11-20 17:21:38 +05:30
Neeraj Gupta
1f0c2d2aa6 Fix lockscreen issue on iPAD (#358)
Tested internally on Simulator and via Test flight.
2023-11-20 15:53:46 +05:30
Zxhir
dc7782fb0c Add the Pingvin Share logo (#356)
<!--
  Thanks for contributing!

Provide a description of your changes below and a general summary in the
title

Please look at the following checklist to ensure that your PR can be
accepted quickly:
-->

## Description

This PR adds the Pingvin Share icon. Pingvin Share is a self-hosted file
sharing platform, their GitHub is
[here](https://github.com/stonith404/pingvin-share) if you want to check
it out.

<!--- Describe your changes in detail -->

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [x] 🖼️ New icon
- [ ]  New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ]  Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] 🧹 Code refactor
- [ ]  Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore
2023-11-18 19:51:26 +05:30
github-actions[bot]
c7ba0c5f33 New Translations (#355) 2023-11-18 19:04:56 +05:30
Neeraj Gupta
5d372607a4 Revert "Analyze qr code image (#336)" (#354)
This reverts commit 233858ad09, reversing
changes made to f97bf015f1.

Reason: media_scanner depends on MLKit that underhood also makes
connection to firebase.
2023-11-17 09:09:22 +05:30
Neeraj Gupta
b203b373b9 Bump version 2.0.18+218 (#352) 2023-11-16 19:17:09 +05:30
github-actions[bot]
a4e12a1e0c New Translations (#351)
New translations via [Crowdin GH
Action](https://github.com/crowdin/github-action)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-11-16 19:11:22 +05:30
Neeraj Gupta
233858ad09 Analyze qr code image (#336) 2023-11-16 15:40:47 +05:30
Neeraj Gupta
863d602a70 Merge branch 'main' into analyzeQrCodeImage 2023-11-16 15:30:08 +05:30
Neeraj Gupta
f97bf015f1 New Translations (#350) 2023-11-16 12:16:08 +05:30
Muhammed Ayimen
9d73a39b9d Updated: Parsing error catched and logged 2023-11-16 15:38:42 +09:00
Muhammed Ayimen
3455e7f7c3 Removed: Unwanted comments in analyze qr code screen 2023-11-16 15:34:44 +09:00
Muhammed Ayimen
e9861e5311 Uncommented: Gradle file contents 2023-11-16 13:21:02 +09:00
Muhammed Ayimen
f902c8ca4c Added: Error handling while parcing qr code data 2023-11-16 13:19:51 +09:00
Muhammed Ayimen
4180621bd9 Bug fixed: Old scanner package using in other places 2023-11-16 13:17:43 +09:00
Muhammed Ayimen
ab2eb77722 Added and removed: Disposal of scanner controller and removal of old scanning package 2023-11-16 13:17:07 +09:00
Muhammed Ayimen
09e6511d64 Removed: Old google auth import scanner 2023-11-16 13:12:03 +09:00
Crowdin Bot
5c4ec23b1a New Crowdin translations by GitHub Action 2023-11-16 00:01:16 +00:00
Muhammed Ayimen
c7a78a70c9 Bug fixed: Google auth image option click function 2023-11-15 08:19:07 +09:00
Muhammed Ayimen
a4df578665 Merge conflict: Resolved-2 2023-11-15 08:12:09 +09:00
Muhammed Ayimen
4cfbe91ad4 Merge conflict: Resolved 2023-11-15 08:08:38 +09:00
Vishnu Mohandas
ae6e910e84 New Translations (#346) 2023-11-14 21:14:36 +05:30
Crowdin Bot
533e0c413a New Crowdin translations by GitHub Action 2023-11-14 14:57:08 +00:00
Vishnu Mohandas
4ec71f6151 Bitwarden import (#348) 2023-11-14 20:26:18 +05:30
Muhammed Ayimen
adc157fe56 Fixes: Based on the review 2023-11-14 23:42:53 +09:00
Muhammed Ayimen
3b8219020a Updated: en arb file content for bitwarden data 2023-11-14 23:40:40 +09:00
Muhammed Ayimen
9b759a02a5 Completed: Import from bitwarden functionality 2023-11-14 23:06:02 +09:00
Muhammed Ayimen
bed3bd9612 Bug fixed: Using the map values from wrong jsonArray 2023-11-14 23:05:43 +09:00
Muhammed Ayimen
27c8111e63 Created: Bitward import functionality with json file selecting and extracting the data to a particular format 2023-11-14 23:05:02 +09:00
Muhammed Ayimen
4b66689e07 Created: Popup for bitwarden import option 2023-11-14 23:04:21 +09:00
Muhammed Ayimen
f22b0cde8d Added: Bitwarden option in import screen 2023-11-14 23:04:05 +09:00
Muhammed Ayimen
1705229ad9 Merge conflict: Resolved 2023-11-14 17:47:22 +09:00
Muhammed Ayimen
baa941c9dd Merge branch 'main' of https://github.com/i-aiymen/auth into analyzeQrCodeImage 2023-11-14 17:45:10 +09:00
Neeraj Gupta
55e9a7049e Lock screen fixes (#345) 2023-11-14 10:39:52 +05:30
Neeraj Gupta
6b4b69f0bb Bump version 2.0.17 2023-11-14 10:35:19 +05:30
Neeraj Gupta
572417d3aa Fix bug in setting showingLockScreen flag 2023-11-14 10:35:00 +05:30
Neeraj Gupta
90193eaed9 Fix import 2023-11-14 10:30:19 +05:30
Neeraj Gupta
d80f783013 Remove commented out code 2023-11-14 10:29:59 +05:30
Neeraj Gupta
16c36a088f bump version 2023-11-14 10:28:35 +05:30
Neeraj Gupta
c0444680c6 Extract strings for local auth 2023-11-14 10:25:02 +05:30
Neeraj Gupta
03b1accfda Add lockscreen fixes from photos 2023-11-14 10:21:03 +05:30
Muhammed Ayimen
8e379a8e43 Uncommmented: Gradle file contents 2023-11-13 20:42:30 +09:00
Muhammed Ayimen
e05bd71fe1 Extracted: All the string added in the Qr code scanning and analyzing image to en arb files 2023-11-13 20:38:49 +09:00
Muhammed Ayimen
5cc4d8cfb3 Updated: allowing only images to be selected for analyzing the Qr code 2023-11-13 20:26:30 +09:00
Vishnu Mohandas
c359775ebc Support multiple names for the same service (#344) 2023-11-13 16:42:08 +05:30
Vishnu Mohandas
80148f95af Merge branch 'main' into support_multiple_names 2023-11-13 16:33:16 +05:30
vishnukvmd
16bb23d977 Support multiple names for the same service 2023-11-13 16:32:08 +05:30
Vishnu Mohandas
0e59f80999 Update icons (#341) 2023-11-12 12:19:16 +05:30
vishnukvmd
a13d2a065e Update icon for mstdn.* 2023-11-12 10:31:28 +05:30
vishnukvmd
993bf81e43 Update simple icons 2023-11-12 10:04:50 +05:30
Muhammed Ayimen
71f3ce4120 Changed: Settings.json file 2023-11-12 13:03:16 +09:00
Muhammed Ayimen
694662d851 Uncommmented: Gradle file contents 2023-11-12 12:57:30 +09:00
Muhammed Ayimen
492748f854 Added: Reminder Popup after analyzing a Qr Code image from gallery 2023-11-12 12:56:26 +09:00
Muhammed Ayimen
c6811ffadc Updated: Different toast, based different condition 2023-11-12 12:23:24 +09:00
Muhammed Ayimen
d432f08dc6 Added: Vibration effect, when google auth Qr code scanning is successfull 2023-11-12 12:16:03 +09:00
Muhammed Ayimen
2930f22208 Added: Functionality to capture the QR codes by scanning it and checking if the QR code is associated with google auth and reject all the QR ccodes 2023-11-12 12:15:25 +09:00
Muhammed Ayimen
b52de5d9e6 Added: Popup while selecting google auth saved image option similar to normal google auth option 2023-11-12 12:05:27 +09:00
Muhammed Ayimen
fd6b030dff Removed: Unwanted permissions from manifest file 2023-11-10 07:58:28 +09:00
Muhammed Ayimen
ae07e435ae Merge branch 'analyzeQrCodeImage' of https://github.com/i-aiymen/auth into analyzeQrCodeImage 2023-11-09 08:03:47 +09:00
Muhammed Ayimen
abab8df412 Updated: Build gradle and settings.json file to initial values 2023-11-08 22:30:37 +09:00
Muhammed Ayimen
c0cc5f29e1 Re-Updated: Location of icons used in qr-code-scanner screen and added the location to the pubspec 2023-11-08 22:27:14 +09:00
Muhammed Ayimen
cd817f6df9 Re-Updated: Location of icons used in qr-code-scanner screen 2023-11-08 22:21:10 +09:00
Muhammed Ayimen
2d56c656cc Updated: Location of icons used in qr-code-scanner screen 2023-11-08 22:12:07 +09:00
Muhammed Ayimen
b33ec5e347 Removed: Unwanted permisions from manifest file 2023-11-08 22:08:53 +09:00
Muhammed Ayimen
3bdfebfcea Added: Comments for different widgets used 2023-11-08 21:47:59 +09:00
Vishnu Mohandas
02d2db92c2 New Translations (#335) 2023-11-08 18:14:12 +05:30
Muhammed Ayimen
3db1c55ce3 Function added: Qr Code Image analyzing by uploading from gallery and scanning Qr code images directly 2023-11-08 21:25:01 +09:00
Crowdin Bot
8ed5bd84d2 New Crowdin translations by GitHub Action 2023-11-08 12:01:18 +00:00
Vishnu Mohandas
7855e3925a New Translations (#328) 2023-11-06 14:11:38 +05:30
Crowdin Bot
f5125b7981 New Crowdin translations by GitHub Action 2023-11-06 00:01:05 +00:00
Vishnu Mohandas
5b11569ea9 New Translations (#325) 2023-11-05 20:33:41 +05:30
Crowdin Bot
c2dc0e6318 New Crowdin translations by GitHub Action 2023-11-05 12:01:21 +00:00
Neeraj Gupta
4ab4b51b56 Reformat code (#323) 2023-10-31 11:41:41 +05:30
vishnukvmd
25c84d5b56 Reformat code 2023-10-31 10:56:04 +05:30
Neeraj Gupta
8f7cf104ed New Translations (#322) 2023-10-31 06:40:17 +05:30
Crowdin Bot
dfc21f60a8 New Crowdin translations by GitHub Action 2023-10-31 00:01:26 +00:00
Neeraj Gupta
ed3067d9d2 New Translations (#321) 2023-10-27 11:43:24 +05:30
Crowdin Bot
459e501700 New Crowdin translations by GitHub Action 2023-10-27 00:01:16 +00:00
Neeraj Gupta
67c5452dee Fix invalid json for custom icons + bump version (#320) 2023-10-25 13:21:11 +05:30
Neeraj Gupta
b847880d41 bump version 2.0.15+215 2023-10-25 12:54:03 +05:30
Neeraj Gupta
257e4e1486 Swallow error in during icon json load 2023-10-25 12:52:49 +05:30
Neeraj Gupta
f8f13f9c8c Fix json 2023-10-25 12:51:11 +05:30
Neeraj Gupta
4bfe69bc47 Downgrade file saver (#319) 2023-10-25 10:01:44 +05:30
Neeraj Gupta
322eb273cd Downgrade file saver 2023-10-25 09:57:27 +05:30
Neeraj Gupta
6bb7db7d54 Add dev_test_icon (#318) 2023-10-25 09:57:01 +05:30
Neeraj Gupta
d077109bc8 New Translations (#317) 2023-10-25 09:43:38 +05:30
Crowdin Bot
ed8aef8f80 New Crowdin translations by GitHub Action 2023-10-25 00:01:02 +00:00
Tanguy
bb1f730e32 Add dev_test_icon
Test icon for verifying SVG behaviour in the release version
2023-10-24 19:47:35 +02:00
Neeraj Gupta
afaf26a2f2 Bump version 2.0.13+213 2023-10-24 10:57:12 +05:30
Vishnu Mohandas
d7a2597406 Change Firefox logo name to Mozilla (#312) 2023-10-24 09:11:15 +05:30
Neeraj Gupta
226aeafe76 Warn accounts are linked with all ente apps before deleting account (#314) 2023-10-24 06:44:06 +05:30
Tanguy
d4a6363793 Merge branch 'main' into my-changes 2023-10-23 19:08:35 +02:00
Neeraj Gupta
249a8016a1 New Translations (#310) 2023-10-23 20:20:32 +05:30
ashilkn
f914256510 Move new mapping to bottom 2023-10-23 19:33:51 +05:30
ashilkn
a9bc28ad02 before deleting account, warn that all ente apps use the same account and deleting the account will wipe out data from all apps 2023-10-23 19:23:31 +05:30
Crowdin Bot
4d89a0ed4a New Crowdin translations by GitHub Action 2023-10-23 12:01:17 +00:00
Tanguy
3475e3a988 Change Firefox logo name to Mozilla
Mozilla has announced the end of Firefox accounts, which will all be renamed as Mozilla accounts. "Firefox" title will continue to work by pointing to the file mozilla.svg.
2023-10-22 16:09:45 +02:00
Vishnu Mohandas
4b246174b6 Update issue templates (#306) 2023-10-21 12:10:49 +05:30
Vishnu Mohandas
aad130fdcb Create CODE_OF_CONDUCT.md (#305) 2023-10-21 12:10:34 +05:30
Vishnu Mohandas
cf4ff27e9a Update issue templates 2023-10-21 11:47:17 +05:30
Vishnu Mohandas
a25925aa6d Create CODE_OF_CONDUCT.md 2023-10-21 11:46:22 +05:30
Neeraj Gupta
7c77c03487 Fix log export for android (#302) 2023-10-20 17:46:57 +05:30
Neeraj Gupta
f549e2e268 Fix Instagram logo (#304) 2023-10-20 17:46:38 +05:30
Tanguy
4b1b27a243 Merge branch 'main' into my-changes 2023-10-20 07:55:43 +02:00
Tanguy
ea915489b8 Fix Instagram logo
Quick fix Instagram logo since Flutter is not compatible with SVG <pattern>
2023-10-20 07:52:14 +02:00
Vishnu Mohandas
e211239ed6 Bunch together app specific settings (#303) 2023-10-19 21:19:40 +05:30
vishnukvmd
a09a4e5c9b Bunch together app specific settings 2023-10-19 21:03:35 +05:30
Neeraj Gupta
7c552a1e8c minor refactor 2023-10-19 15:41:54 +05:30
Neeraj Gupta
518eb1d942 Fix log export for android 2023-10-19 15:23:51 +05:30
Neeraj Gupta
ec895546f6 Bump version to 2.0.12 2023-10-19 12:50:48 +05:30
Neeraj Gupta
f5b7894cb1 Show placeholder icons when icon is missing (#301) 2023-10-19 12:48:31 +05:30
Neeraj Gupta
3f5ef23e1b Update ui 2023-10-19 12:46:03 +05:30
Neeraj Gupta
d496adaed2 Show placeholder icons when icon is missing 2023-10-19 12:38:27 +05:30
Neeraj Gupta
016e85f350 Bump version to 2.0.11 2023-10-19 12:20:03 +05:30
Neeraj Gupta
cab66cdea0 Bump version to 2.0.10 2023-10-19 11:57:01 +05:30
Neeraj Gupta
6869cf9c1d Fix: Show confirmation dialog when secrets are updated (#299) 2023-10-19 11:56:04 +05:30
Neeraj Gupta
1b4a9fb12e Merge branch 'main' into fix_save_bug 2023-10-19 11:55:09 +05:30
Neeraj Gupta
20ab1d75d2 Fix: Show confirmation during edit when secret is updated 2023-10-19 11:54:23 +05:30
Neeraj Gupta
68de8b8d39 Fix broken icon for Github and UbiSoft 2023-10-19 11:48:37 +05:30
Neeraj Gupta
40f6def104 Bump version 2.0.9+209 (#298) 2023-10-19 11:42:20 +05:30
Neeraj Gupta
6460396f8d Merge branch 'main' into bump_version 2023-10-19 11:16:37 +05:30
Neeraj Gupta
8aa3d28981 Bump version 2.0.9+209 2023-10-19 11:15:52 +05:30
Neeraj Gupta
2ec537c65f Fix edit/del when device authentication is not supported (#297) 2023-10-19 10:29:22 +05:30
Neeraj Gupta
2448e8d011 Fix edit/del when device authentication is not supported 2023-10-19 10:09:03 +05:30
Neeraj Gupta
4917b65a0b Disable swipe to open hamburger menu on droid (#296) 2023-10-19 09:55:04 +05:30
Neeraj Gupta
f57108c708 Merge branch 'main' into droid_disable_swipe_to_open_hamburger 2023-10-19 09:54:57 +05:30
Neeraj Gupta
e29cb24458 Disable swipe to open hamburger menu on droid 2023-10-19 09:53:54 +05:30
Vishnu Mohandas
e42b469965 Add missing slugs to titles with space (#295) 2023-10-19 07:15:08 +05:30
Vishnu Mohandas
964a333893 Add and normalise logos (#292) 2023-10-19 07:14:12 +05:30
Sven
78af7dec6c add slug to titles with space 2023-10-18 22:47:48 +02:00
Tanguy
e96cc96494 Add Snapchat logo data 2023-10-17 21:17:41 +02:00
Tanguy
3eb538ba59 Add Snapchat logo 2023-10-17 21:14:36 +02:00
Tanguy
add3264e4f Merge branch 'main' into my-changes 2023-10-13 22:21:36 +02:00
Tanguy
0ae1efa133 Add NVIDIA logo 2023-10-13 22:15:54 +02:00
Tanguy
f38c2bead4 Update Google logo
Normalise SVG
2023-10-13 22:08:49 +02:00
Tanguy
c3f5574d77 Update GitHub logo
Normalise SVG and add mix-blend-mode:difference for dark/light mode
2023-10-13 22:04:28 +02:00
Tanguy
9fa6d5f6a7 Update Ubisoft logo
Normalise Ubisoft SVG and add mix-blend-mode:difference for dark/light mode
2023-10-13 21:58:09 +02:00
Tanguy
c59c34b40d Add Notion logo 2023-10-13 21:51:01 +02:00
Tanguy
3f646b6f53 Add Cloudflare logo 2023-10-13 21:50:51 +02:00
Tanguy
122a05e1b9 Add Bitwarden logo 2023-10-13 21:21:51 +02:00
Vishnu Mohandas
b1745466a2 Add a bunch of logos (#291) 2023-10-13 23:39:54 +05:30
Tanguy
ba29be811c Update X (Twitter) logo for dark/light mode
Set mix-blend-mode:difference to enhance SVG visibility in light mode
2023-10-13 18:24:22 +02:00
Tanguy
afedf5947d Fix PayPal logo offset
Fix 1 px offset in SVG
2023-10-13 18:22:36 +02:00
Tanguy
07740023ff Fix La Poste logo offset
Fix 1 px offset in SVG
2023-10-13 18:22:13 +02:00
Tanguy
0979a0d544 Fix Firefox logo offset
Fix 1 px offset in SVG
2023-10-13 18:21:24 +02:00
Tanguy
a79063acc2 Fix Firefox logo size
Set SVG size to 500px × 500px
2023-10-12 20:38:27 +02:00
Tanguy
0dc78e3a87 Fix PayPal logo size
Set SVG size to 500px × 500px
2023-10-12 20:30:25 +02:00
Tanguy
00cb6888bd Add Proton logo 2023-10-12 20:12:43 +02:00
Tanguy
e86ba39909 Add X (Twitter) logo 2023-10-12 20:06:37 +02:00
Tanguy
48f6eee008 Add PayPal logo 2023-10-12 19:57:12 +02:00
Tanguy
23b98d5ff0 Add Instagram logo 2023-10-12 19:50:34 +02:00
Tanguy
03c28698e2 Add Microsoft logo 2023-10-12 19:45:50 +02:00
Tanguy
cbf2dfebe5 Add Firefox logo 2023-10-12 19:40:53 +02:00
Tanguy
7e6ea8fbfd Update La Poste logo size
Set SVG size to 500px × 500px
2023-10-12 19:39:13 +02:00
Neeraj Gupta
4e73836baa Adding La Poste logo (#289) 2023-10-12 10:12:59 +05:30
Vishnu Mohandas
4dbae7c8fa New Translations (#290) 2023-10-12 09:31:59 +05:30
Crowdin Bot
649aa69cf8 New Crowdin translations by GitHub Action 2023-10-12 00:01:16 +00:00
Tanguy
0ba50722f6 Adding La Poste logo 2023-10-11 21:40:20 +02:00
Vishnu Mohandas
ead6fd6d0d Remove redundant warning (#288) 2023-10-11 19:41:03 +05:30
vishnukvmd
f5e4a2ac88 v2.0.8 2023-10-11 19:17:58 +05:30
vishnukvmd
f6d32e22f2 Remove warning while saving a new code 2023-10-11 19:17:35 +05:30
Neeraj Gupta
cad9f00ebe Bump version 2.0.7+207 (#285) 2023-10-10 11:11:45 +05:30
Neeraj Gupta
1fb163d561 Fix translation 2023-10-10 10:58:31 +05:30
Neeraj Gupta
2c82bdc8a3 Bump version to 2.0.7+207 2023-10-10 10:51:49 +05:30
Vishnu Mohandas
ccf51fe139 New Translations (#284) 2023-10-09 19:59:29 +05:30
Crowdin Bot
9c56c0abbc New Crowdin translations by GitHub Action 2023-10-09 12:01:12 +00:00
Vishnu Mohandas
ea1827d963 Added authentication when pressing the Share QR, edit and delete button (#277) 2023-10-06 22:11:24 +05:30
Shivam Pachchigar
c441068857 Typo in QR code authentication message 2023-10-06 21:56:47 +05:30
Vishnu Mohandas
c7e917dacf New Translations (#283) 2023-10-06 20:54:22 +05:30
Shivam Pachchigar
262a49439d Added locales 2023-10-06 19:39:24 +05:30
Shivam Pachchigar
a552783f59 Merge branch 'ente-io:main' into main 2023-10-06 18:25:24 +05:30
Crowdin Bot
5658bd6ecf New Crowdin translations by GitHub Action 2023-10-06 12:01:23 +00:00
Neeraj Gupta
2742db3d5b New Translations (#282) 2023-10-06 06:56:19 +05:30
Crowdin Bot
2344cfda91 New Crowdin translations by GitHub Action 2023-10-06 00:24:44 +00:00
Neeraj Gupta
8f33182c18 New Translations (#280) 2023-10-05 19:47:03 +05:30
Crowdin Bot
2eb9dddf1d New Crowdin translations by GitHub Action 2023-10-05 12:10:02 +00:00
Neeraj Gupta
432e9d77a1 Added Skiff and NextDNS (#278) 2023-10-05 16:12:32 +05:30
Brogio
dbcfbf0824 Update custom-icons.json
Forgot comma
2023-10-05 12:19:24 +02:00
Brogio
3994470117 Update custom-icons.json
Added NextDNS and Skiff
2023-10-05 12:16:39 +02:00
Brogio
fce76ac629 Add files via upload 2023-10-05 12:12:27 +02:00
Shivam Pachchigar
a2d0c3c3d9 Merge branch 'ente-io:main' into main 2023-10-05 15:18:12 +05:30
Shivam Pachchigar
62a41c89c6 Added authentication to show QR, edit or delete a code
- Used the requestAuthentication function in utils/auth_util.dart to perform the authentication
2023-10-05 15:11:38 +05:30
Vishnu Mohandas
31ce98453e feat(screen-refresh-rate): use flutter_displaymode to enable high refresh rates on devices with refresh rate locked at 60FPS (#276) 2023-10-05 13:39:59 +05:30
ashilkn
858ba41f8b Merge main 2023-10-05 13:37:29 +05:30
ashilkn
02750dd8da feat(screen-refresh-rate): use flutter_displaymode to enable high refresh rates in devices with refresh rate locked at 60FPS 2023-10-05 13:29:15 +05:30
ashilkn
25f9b02e53 chore: run dart fix --apply to add trailing commas 2023-10-05 13:13:59 +05:30
Neeraj Gupta
eaca45f5fe New Translations (#272) 2023-10-02 08:03:31 +05:30
Crowdin Bot
ef2b9c5fcd New Crowdin translations by GitHub Action 2023-10-02 00:25:05 +00:00
Vishnu Mohandas
a5a287912b feature/264 - Add clipboard minimize (#273) 2023-10-01 23:36:11 +05:30
Hubert
8dc06464c7 Add minimize on copy 2023-10-01 18:47:13 +02:00
Hubert
5c6eaa9fb9 Fix require_trailing_commas 2023-10-01 17:45:15 +02:00
Vishnu Mohandas
c53ac484fa Require confirmation during Save if Secret Key (#271) 2023-10-01 17:05:17 +05:30
Ahsan Ahmad
573b3a321d Require confirmation during Save if Secret Key 2023-10-01 16:05:35 +05:00
Vishnu Mohandas
7072b14073 New Translations (#270) 2023-10-01 16:32:48 +05:30
Crowdin Bot
8c67e54396 New Crowdin translations by GitHub Action 2023-10-01 00:29:00 +00:00
Vishnu Mohandas
92bfa153f1 Update screenshots (#269) 2023-09-29 16:56:25 +05:30
vishnukvmd
47c5ed25e7 Update screenshots 2023-09-29 16:43:48 +05:30
Vishnu Mohandas
09e7bae985 Update banner (#268) 2023-09-29 16:17:35 +05:30
Vishnu Mohandas
54ecafdafc Merge branch 'main' into update_banner 2023-09-29 16:14:02 +05:30
vishnukvmd
265e74aff9 v2.0.6 2023-09-29 16:12:52 +05:30
vishnukvmd
75a41bc724 Update the banner 2023-09-29 16:12:07 +05:30
104 changed files with 4941 additions and 624 deletions

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
community@ente.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -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
[![Crowdin](https://badges.crowdin.net/ente-authenticator-app/localized.svg)](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";

View File

@@ -7,6 +7,9 @@
"title": "Addy.io",
"slug": "addy_io"
},
{
"title": "Airtable"
},
{
"title": "Anycoin Direct",
"slug": "anycoindirect"
@@ -24,6 +27,9 @@
"title": "Bitvavo",
"hex": "0051FF"
},
{
"title": "Bitwarden"
},
{
"title": "Bybit"
},
@@ -32,10 +38,21 @@
"slug": "cih",
"hex": "D14633"
},
{
"title": "Cloudflare"
},
{
"title": "Control D",
"slug": "controld",
"hex": "5FD800"
},
{
"title": "Discourse"
},
{
"title": "dus.net",
"slug": "dusnet"
},
{
"title": "ente",
"hex": "1DB954"
@@ -45,7 +62,11 @@
"hex": "858585"
},
{
"title": "Github",
"title": "Firefox",
"slug": "mozilla"
},
{
"title": "GitHub",
"hex": "858585"
},
{
@@ -54,6 +75,12 @@
{
"title": "ING"
},
{
"title": "INWX"
},
{
"title": "Instagram"
},
{
"title": "Jagex",
"hex": "D3D800"
@@ -77,6 +104,22 @@
"title": "KuCoin",
"hex": "01BC8D"
},
{
"title": "La Poste",
"slug": "laposte"
},
{
"title": "Mastodon",
"altNames": ["mstdn", "fediscience", "mathstodon", "fosstodon"],
"slug": "mastodon",
"hex": "6364FF"
},
{
"title": "Microsoft"
},
{
"title": "Mozilla"
},
{
"title": "ngrok",
"hex": "858585"
@@ -84,16 +127,29 @@
{
"title": "Njalla"
},
{
"title": "Notion"
},
{
"title": "NVIDIA"
},
{
"title": "Odido"
},
{
"title": "Parsec"
},
{
"title": "PayPal"
},
{
"title": "Peerberry",
"hex": "03E5A5"
},
{
"title": "Pingvin Share",
"hex": "485099"
},
{
"title": "Plutus",
"hex": "DEC685"
@@ -110,20 +166,38 @@
"color": "EF8300"
},
{
"title": "Privacy Guides"
"title": "Privacy Guides",
"slug": "privacyguides"
},
{
"title": "Privacy.com"
"title": "Privacy.com",
"slug": "privacy"
},
{
"title": "Proton"
},
{
"title": "Proxmox"
},
{
"title": "Revolt",
"hex": "858585"
},
{
"title": "service-bw"
},
{
"title": "SimpleLogin"
},
{
"title": "Sipgate"
},
{
"title": "Snapchat"
},
{
"title": "Standard Notes",
"slug": "standardnotes",
"hex": "2173E6"
},
{
@@ -135,6 +209,7 @@
},
{
"title": "Trading 212",
"slug": "trading212",
"hex": "4BA4DE"
},
{
@@ -170,6 +245,18 @@
},
{
"title": "Wise"
},
{
"title": "X",
"altNames": ["twitter"],
"slug": "x"
},
{
"title": "NextDNS"
},
{
"title": "Skiff",
"hex": "EF5A3C"
}
]
}

View 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

View File

@@ -0,0 +1,11 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8_67)">
<path d="M500 421.875C500 465.039 465.039 500 421.875 500H78.125C34.9609 500 0 465.039 0 421.875V78.125C0 34.9609 34.9609 0 78.125 0H421.875C465.039 0 500 34.9609 500 78.125V421.875Z" fill="#175DDC"/>
<path d="M405.176 62.793C402.002 59.6191 398.242 58.0566 393.945 58.0566H106.055C101.709 58.0566 97.998 59.6191 94.8242 62.793C91.6504 65.9668 90.0879 69.7266 90.0879 74.0234V265.967C90.0879 280.273 92.8711 294.482 98.4375 308.594C104.004 322.656 110.938 335.156 119.189 346.094C127.441 356.982 137.256 367.627 148.682 377.978C160.107 388.33 170.654 396.875 180.273 403.711C189.941 410.547 200 416.992 210.498 423.096C220.996 429.199 228.467 433.301 232.861 435.449C237.256 437.598 240.82 439.307 243.457 440.43C245.459 441.406 247.607 441.943 249.951 441.943C252.295 441.943 254.443 441.455 256.445 440.43C259.131 439.258 262.646 437.598 267.09 435.449C271.484 433.301 278.955 429.15 289.453 423.096C299.951 416.992 310.01 410.547 319.678 403.711C329.346 396.875 339.893 388.281 351.318 377.978C362.744 367.627 372.559 357.031 380.811 346.094C389.063 335.156 395.947 322.705 401.563 308.594C407.129 294.531 409.912 280.322 409.912 265.967V74.0723C409.961 69.7266 408.35 65.9668 405.176 62.793ZM368.066 267.773C368.066 337.256 250 397.119 250 397.119V99.1699H368.066C368.066 99.1699 368.066 198.291 368.066 267.773Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_8_67">
<rect width="500" height="500" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,4 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M341.368 359.947L343.921 351.059C346.952 340.494 345.83 330.743 340.724 323.556C335.951 316.944 328.172 313.063 318.652 312.608L138.423 310.308C137.857 310.3 137.302 310.155 136.805 309.885C136.307 309.614 135.882 309.228 135.566 308.757C135.249 308.286 135.051 307.746 134.988 307.182C134.924 306.617 134.998 306.046 135.202 305.517C135.508 304.63 136.067 303.853 136.809 303.282C137.552 302.711 138.445 302.372 139.377 302.306L321.348 299.911C342.824 298.929 366.304 281.344 374.488 259.879L384.844 232.664C385.138 231.9 385.284 231.087 385.274 230.268C385.262 229.833 385.214 229.401 385.131 228.974C379.481 203.66 365.746 180.894 346.018 164.141C326.29 147.388 301.649 137.566 275.848 136.172C250.046 134.778 224.498 141.887 203.093 156.417C181.687 170.947 165.598 192.102 157.274 216.66C148.437 210.066 137.785 206.379 126.778 206.106C115.772 205.833 104.951 208.986 95.8004 215.133C86.65 221.28 79.6189 230.12 75.6722 240.44C71.7255 250.759 71.0566 262.051 73.7573 272.768C63.0348 273.046 52.4935 275.608 42.8317 280.285C33.17 284.962 24.6082 291.646 17.7136 299.896C10.819 308.145 5.74894 317.771 2.83918 328.136C-0.0705683 338.501 -0.753564 349.369 0.835439 360.019C0.950401 360.859 1.36372 361.63 1.9994 362.189C2.63508 362.748 3.45038 363.058 4.29541 363.061H337.145C338.089 363.071 339.012 362.772 339.773 362.211C340.535 361.649 341.094 360.855 341.368 359.947Z" fill="#F4801F"/>
<path d="M401.428 234.724C399.838 234.724 398.167 234.772 396.417 234.868C396.155 234.875 395.896 234.932 395.654 235.035C395.218 235.18 394.824 235.431 394.508 235.765C394.192 236.1 393.962 236.507 393.84 236.952L386.682 261.532C383.627 272.097 384.749 281.847 389.879 289.034C392.471 292.435 395.808 295.191 399.632 297.09C403.455 298.989 407.662 299.978 411.928 299.983L450.369 302.378C450.907 302.395 451.433 302.538 451.905 302.796C452.378 303.054 452.783 303.42 453.089 303.864C453.414 304.338 453.62 304.884 453.691 305.455C453.761 306.026 453.694 306.606 453.495 307.146C453.189 308.033 452.63 308.81 451.887 309.381C451.145 309.951 450.252 310.29 449.319 310.356L409.398 312.752C387.708 313.758 364.347 331.318 356.162 352.76L353.275 360.33C353.154 360.647 353.11 360.988 353.145 361.326C353.181 361.663 353.295 361.987 353.478 362.272C353.662 362.557 353.91 362.794 354.202 362.965C354.495 363.135 354.823 363.234 355.16 363.253H492.676C493.514 363.273 494.335 363.007 495.002 362.497C495.67 361.988 496.146 361.266 496.351 360.45C500.45 345.742 501.106 330.281 498.266 315.276C495.427 300.271 489.169 286.129 479.982 273.955C470.796 261.781 458.929 251.905 445.31 245.099C431.691 238.294 416.689 234.743 401.476 234.724H401.428Z" fill="#F9AB41"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View 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

View 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

View File

@@ -1 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="64" height="64"><defs><path id="A" d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"/></defs><clipPath id="B"><use xlink:href="#A"/></clipPath><g transform="matrix(.727273 0 0 .727273 -.954545 -1.45455)"><path d="M0 37V11l17 13z" clip-path="url(#B)" fill="#fbbc05"/><path d="M0 11l17 13 7-6.1L48 14V0H0z" clip-path="url(#B)" fill="#ea4335"/><path d="M0 37l30-23 7.9 1L48 0v48H0z" clip-path="url(#B)" fill="#34a853"/><path d="M48 48L17 24l-4-3 35-10z" clip-path="url(#B)" fill="#4285f4"/></g></svg>
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M495 255.682C495 237.955 493.409 220.909 490.455 204.545H255V301.364H389.545C383.636 332.5 365.909 358.864 339.318 376.591V439.545H420.455C467.727 395.909 495 331.818 495 255.682Z" fill="#4285F4"/>
<path d="M254.998 499.999C322.498 499.999 379.089 477.727 420.453 439.545L339.317 376.59C317.044 391.59 288.635 400.681 254.998 400.681C189.998 400.681 134.771 356.818 114.998 297.727H31.8167V362.272C72.953 443.863 157.271 499.999 254.998 499.999Z" fill="#34A853"/>
<path d="M115 297.499C110 282.499 107.045 266.59 107.045 249.999C107.045 233.408 110 217.499 115 202.499V137.953H31.8182C14.7727 171.59 5 209.544 5 249.999C5 290.453 14.7727 328.408 31.8182 362.044L96.5909 311.59L115 297.499Z" fill="#FBBC05"/>
<path d="M254.998 99.5455C291.817 99.5455 324.544 112.273 350.68 136.818L422.271 65.2273C378.862 24.7727 322.498 0 254.998 0C157.271 0 72.953 56.1364 31.8167 137.955L114.998 202.5C134.771 143.409 189.998 99.5455 254.998 99.5455Z" fill="#EA4335"/>
</svg>

Before

Width:  |  Height:  |  Size: 757 B

After

Width:  |  Height:  |  Size: 1.0 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 118 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,3 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M113.22 144.994L222.135 194.471H388.952L402.763 170.591C411.046 156.238 401.045 139 385.937 139H114.404C113.68 138.996 112.977 139.244 112.417 139.702C111.857 140.16 111.474 140.799 111.333 141.508C111.193 142.218 111.305 142.954 111.65 143.591C111.994 144.227 112.549 144.723 113.22 144.994ZM222.135 215.71H493.862C495.344 215.723 496.773 216.267 497.888 217.244C499.003 218.22 499.731 219.563 499.939 221.03C500.147 222.497 499.821 223.99 499.021 225.237C498.222 226.485 497.001 227.404 495.58 227.828L3.93325 360.885C3.24581 361.078 2.51276 361.027 1.85828 360.742C1.20379 360.457 0.668087 359.954 0.341912 359.319C0.0157368 358.684 -0.0808603 357.956 0.0684733 357.258C0.217807 356.561 0.603887 355.936 1.16134 355.49L222.135 215.71ZM263.114 357.759L84.8044 360.999L331.309 294.317L309.928 331.432C300.673 347.471 280.41 357.435 263.114 357.759Z" fill="#003DA5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,13 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_120_68)">
<path d="M0 0H238.095V238.095H0V0Z" fill="#F35325"/>
<path d="M261.905 0H500V238.095H261.905V0Z" fill="#81BC06"/>
<path d="M0 261.905H238.095V500H0V261.905Z" fill="#05A6F0"/>
<path d="M261.905 261.905H500V500H261.905V261.905Z" fill="#FFBA08"/>
</g>
<defs>
<clipPath id="clip0_120_68">
<rect width="500" height="500" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 493 B

View File

@@ -0,0 +1,112 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_7)">
<path d="M449.654 98.1278C404.468 38.6202 334.019 1.53338 259.925 0.0547762C201.883 -1.10346 161.778 16.3386 139.088 30.3608C169.446 12.7546 213.373 2.76876 251.835 3.26003C350.78 4.52365 457.038 71.8955 472.82 193.345C490.937 332.758 393.84 449.114 257.237 449.466C106.955 449.852 15.5524 316.787 39.4413 197.267C40.6343 191.299 40.0388 185.493 42.0276 179.853C43.166 158.838 51.1048 125.897 68.2302 92.2396C50.9267 101.192 28.8901 129.518 18.0097 155.755C2.32437 193.58 -3.20344 238.813 1.77266 281.848C2.14727 285.086 2.48657 288.317 2.91021 291.529C23.0382 409.89 125.845 500 249.662 500C387.921 500 500.001 387.654 500.001 249.068C500.001 192.404 481.256 140.133 449.654 98.1278Z" fill="url(#paint0_radial_1_7)"/>
<g opacity="0.67">
<path d="M449.654 98.1278C404.468 38.6202 334.019 1.53338 259.925 0.0547762C201.883 -1.10346 161.778 16.3386 139.088 30.3608C169.446 12.7546 213.373 2.76876 251.835 3.26003C350.78 4.52365 457.038 71.8955 472.82 193.345C490.937 332.758 393.84 449.114 257.237 449.466C106.955 449.852 15.5524 316.787 39.4413 197.267C40.6343 191.299 40.0388 185.493 42.0276 179.853C43.166 158.838 51.1048 125.897 68.2302 92.2396C50.9267 101.192 28.8901 129.518 18.0097 155.755C2.32437 193.58 -3.20344 238.813 1.77266 281.848C2.14727 285.086 2.48657 288.317 2.91021 291.529C23.0382 409.89 125.845 500 249.662 500C387.921 500 500.001 387.654 500.001 249.068C500.001 192.404 481.256 140.133 449.654 98.1278Z" fill="url(#paint1_radial_1_7)"/>
</g>
<path d="M449.654 98.1278C404.468 38.6202 334.019 1.53338 259.925 0.0547762C201.883 -1.10346 161.778 16.3386 139.088 30.3608C169.446 12.7546 213.373 2.76876 251.835 3.26003C350.78 4.52365 457.038 71.8955 472.82 193.345C490.937 332.758 393.84 449.114 257.237 449.466C106.955 449.852 15.5524 316.787 39.4413 197.267C40.6343 191.299 40.0388 185.493 42.0276 179.853C43.166 158.838 51.1048 125.897 68.2302 92.2396C50.9267 101.192 28.8901 129.518 18.0097 155.755C2.32437 193.58 -3.20344 238.813 1.77266 281.848C2.14727 285.086 2.48657 288.317 2.91021 291.529C23.0382 409.89 125.845 500 249.662 500C387.921 500 500.001 387.654 500.001 249.068C500.001 192.404 481.256 140.133 449.654 98.1278Z" fill="url(#paint2_radial_1_7)"/>
<path d="M449.654 98.1278C404.468 38.6202 334.019 1.53338 259.925 0.0547762C201.883 -1.10346 161.778 16.3386 139.088 30.3608C169.446 12.7546 213.373 2.76876 251.835 3.26003C350.78 4.52365 457.038 71.8955 472.82 193.345C490.937 332.758 393.84 449.114 257.237 449.466C106.955 449.852 15.5524 316.787 39.4413 197.267C40.6343 191.299 40.0388 185.493 42.0276 179.853C43.166 158.838 51.1048 125.897 68.2302 92.2396C50.9267 101.192 28.8901 129.518 18.0097 155.755C2.32437 193.58 -3.20344 238.813 1.77266 281.848C2.14727 285.086 2.48657 288.317 2.91021 291.529C23.0382 409.89 125.845 500 249.662 500C387.921 500 500.001 387.654 500.001 249.068C500.001 192.404 481.256 140.133 449.654 98.1278Z" fill="url(#paint3_radial_1_7)"/>
<path d="M449.654 98.1278C404.468 38.6202 334.019 1.53338 259.925 0.0547762C201.883 -1.10346 161.778 16.3386 139.088 30.3608C169.446 12.7546 213.373 2.76876 251.835 3.26003C350.78 4.52365 457.038 71.8955 472.82 193.345C490.937 332.758 393.84 449.114 257.237 449.466C106.955 449.852 15.5524 316.787 39.4413 197.267C40.6343 191.299 40.0388 185.493 42.0276 179.853C43.166 158.838 51.1048 125.897 68.2302 92.2396C50.9267 101.192 28.8901 129.518 18.0097 155.755C2.32437 193.58 -3.20344 238.813 1.77266 281.848C2.14727 285.086 2.48657 288.317 2.91021 291.529C23.0382 409.89 125.845 500 249.662 500C387.921 500 500.001 387.654 500.001 249.068C500.001 192.404 481.256 140.133 449.654 98.1278Z" fill="url(#paint4_radial_1_7)"/>
<path d="M472.82 193.345C474.821 208.74 475.411 223.879 474.704 238.634C482.993 237.404 491.298 236.29 499.619 235.324C496.852 183.966 478.684 136.714 449.654 98.1278C404.468 38.6202 334.019 1.53338 259.925 0.0547762C201.883 -1.10346 161.778 16.3386 139.088 30.3608C169.447 12.7546 213.373 2.76876 251.835 3.26003C350.78 4.52365 457.038 71.8955 472.82 193.345Z" fill="url(#paint5_linear_1_7)"/>
<path d="M478.906 186.412C464.837 59.4883 351.644 2.43711 251.835 3.25968C213.372 3.57668 169.447 12.7542 139.088 30.3605C124.907 39.1241 117.529 46.5463 116.84 47.2553C117.645 46.5872 120.05 44.6073 124.039 41.8694C124.17 41.7779 124.302 41.6883 124.433 41.5973C124.546 41.5201 124.665 41.4409 124.78 41.3627C139.252 31.3609 155.585 24.0969 172.857 19.0356C199.234 11.3059 227.794 8.71175 255.252 9.40176C368.133 15.9111 447.791 109.6 450.564 209.328C452.859 291.866 385.3 357.69 307.425 361.502C250.788 364.274 197.438 336.868 171.364 282.041C165.564 269.844 161.31 257.447 159.091 242.46C146.738 159.023 202.77 87.8675 254.153 70.2514C226.429 46.0376 156.976 47.68 105.282 85.7096C68.0543 113.097 43.9045 154.767 35.9036 204.479C29.8035 242.381 35.5487 281.798 50.5293 317C65.7937 352.87 90.6184 384.493 121.828 407.778C155.719 433.064 196.529 447.778 238.591 450.983C244.794 451.455 251.016 451.686 257.237 451.686C422.629 451.686 494.395 326.143 478.906 186.412Z" fill="url(#paint6_radial_1_7)"/>
<path d="M478.906 186.412C464.837 59.4883 351.644 2.43711 251.835 3.25968C213.372 3.57668 169.447 12.7542 139.088 30.3605C124.907 39.1241 117.529 46.5463 116.84 47.2553C117.645 46.5872 120.05 44.6073 124.039 41.8694C124.17 41.7779 124.302 41.6883 124.433 41.5973C124.546 41.5201 124.665 41.4409 124.78 41.3627C139.252 31.3609 155.585 24.0969 172.857 19.0356C199.234 11.3059 227.794 8.71175 255.252 9.40176C368.133 15.9111 447.791 109.6 450.564 209.328C452.859 291.866 385.3 357.69 307.425 361.502C250.788 364.274 197.438 336.868 171.364 282.041C165.564 269.844 161.31 257.447 159.091 242.46C146.738 159.023 202.77 87.8675 254.153 70.2514C226.429 46.0376 156.976 47.68 105.282 85.7096C68.0543 113.097 43.9045 154.767 35.9036 204.479C29.8035 242.381 35.5487 281.798 50.5293 317C65.7937 352.87 90.6184 384.493 121.828 407.778C155.719 433.064 196.529 447.778 238.591 450.983C244.794 451.455 251.016 451.686 257.237 451.686C422.629 451.686 494.395 326.143 478.906 186.412Z" fill="url(#paint7_radial_1_7)"/>
<path opacity="0.53" d="M478.906 186.412C464.837 59.4883 351.644 2.43711 251.835 3.25968C213.372 3.57668 169.447 12.7542 139.088 30.3605C124.907 39.1241 117.529 46.5463 116.84 47.2553C117.645 46.5872 120.05 44.6073 124.039 41.8694C124.17 41.7779 124.302 41.6883 124.433 41.5973C124.546 41.5201 124.665 41.4409 124.78 41.3627C139.252 31.3609 155.585 24.0969 172.857 19.0356C199.234 11.3059 227.794 8.71175 255.252 9.40176C368.133 15.9111 447.791 109.6 450.564 209.328C452.859 291.866 385.3 357.69 307.425 361.502C250.788 364.274 197.438 336.868 171.364 282.041C165.564 269.844 161.31 257.447 159.091 242.46C146.738 159.023 202.77 87.8675 254.153 70.2514C226.429 46.0376 156.976 47.68 105.282 85.7096C68.0543 113.097 43.9045 154.767 35.9036 204.479C29.8035 242.381 35.5487 281.798 50.5293 317C65.7937 352.87 90.6184 384.493 121.828 407.778C155.719 433.064 196.529 447.778 238.591 450.983C244.794 451.455 251.016 451.686 257.237 451.686C422.629 451.686 494.395 326.143 478.906 186.412Z" fill="url(#paint8_radial_1_7)"/>
<path opacity="0.53" d="M478.906 186.412C464.837 59.4883 351.644 2.43711 251.835 3.25968C213.372 3.57668 169.447 12.7542 139.088 30.3605C124.907 39.1241 117.529 46.5463 116.84 47.2553C117.645 46.5872 120.05 44.6073 124.039 41.8694C124.17 41.7779 124.302 41.6883 124.433 41.5973C124.546 41.5201 124.665 41.4409 124.78 41.3627C139.252 31.3609 155.585 24.0969 172.857 19.0356C199.234 11.3059 227.794 8.71175 255.252 9.40176C368.133 15.9111 447.791 109.6 450.564 209.328C452.859 291.866 385.3 357.69 307.425 361.502C250.788 364.274 197.438 336.868 171.364 282.041C165.564 269.844 161.31 257.447 159.091 242.46C146.738 159.023 202.77 87.8675 254.153 70.2514C226.429 46.0376 156.976 47.68 105.282 85.7096C68.0543 113.097 43.9045 154.767 35.9036 204.479C29.8035 242.381 35.5487 281.798 50.5293 317C65.7937 352.87 90.6184 384.493 121.828 407.778C155.719 433.064 196.529 447.778 238.591 450.983C244.794 451.455 251.016 451.686 257.237 451.686C422.629 451.686 494.395 326.143 478.906 186.412Z" fill="url(#paint9_radial_1_7)"/>
<path d="M307.425 361.503C414.316 355.001 460.052 266.526 462.918 203.72C467.395 105.643 409.2 -0.126533 255.252 9.40221C227.794 8.7122 199.234 11.3064 172.857 19.0361C149.734 26.107 133.674 35.352 124.78 41.3631C124.665 41.4427 124.547 41.5179 124.433 41.5978C124.294 41.6919 124.174 41.7775 124.039 41.8698C121.646 43.5471 119.305 45.302 117.019 47.1331C121.299 44.2048 174.389 12.8524 248.148 22.5325C336.512 34.1291 417.329 102.89 417.329 193.616C417.329 263.42 363.381 316.711 300.217 312.907C206.37 307.255 182.739 211.024 231.535 169.445C218.371 166.611 193.632 172.162 176.408 197.914C160.953 221.021 161.826 256.725 171.364 282.042C197.438 336.869 250.824 364.945 307.425 361.503Z" fill="url(#paint10_radial_1_7)"/>
<path d="M449.653 98.128C442.953 89.3023 435.635 81.0359 427.892 73.24C421.681 66.6494 415.025 60.5769 408.035 54.9527C412.063 58.4828 415.94 62.1882 419.589 66.1366C433.126 80.7851 443.847 98.0902 450.1 117.036C463.157 156.595 462.305 206.1 437.378 244.983C407.672 291.317 359.312 314.19 307.033 313.076C304.773 313.086 302.503 313.045 300.216 312.907C206.371 307.254 182.739 211.024 231.536 169.446C218.37 166.611 193.633 172.163 176.409 197.914C160.954 221.021 161.826 256.725 171.365 282.041C165.564 269.845 161.31 257.448 159.092 242.461C146.739 159.024 202.771 87.8674 254.154 70.2515C226.43 46.0383 156.977 47.6807 105.282 85.7101C75.1598 107.87 53.6089 139.387 42.2367 176.943C43.9084 155.87 51.8685 124.396 68.2293 92.2397C50.9275 101.191 28.8895 129.518 18.011 155.754C2.32562 193.58 -3.20326 238.813 1.77207 281.848C2.14848 285.086 2.48726 288.317 2.91018 291.53C23.0374 409.89 125.845 500 249.663 500C387.921 500 500.002 387.654 500.002 249.068C500.002 192.404 481.256 140.134 449.653 98.128Z" fill="url(#paint11_linear_1_7)"/>
<path d="M450.1 117.036C443.847 98.0897 433.126 80.7844 419.588 66.1372C403.638 48.8804 383.775 35.7674 362.749 25.5553C344.86 16.8673 326.178 10.0107 306.871 5.74991C272.289 -1.88175 236.008 -1.7464 203.338 5.14589C167.82 12.6389 136.586 28.0095 116.833 47.2254C131.645 38.2253 152.305 30.926 167.027 27.2063C235.343 9.94493 310.57 28.6413 361.858 77.8279C372.17 87.7169 381.417 98.7823 388.914 110.971C419.511 160.713 416.616 223.248 392.761 260.13C375.039 287.529 337.09 313.232 301.682 312.954C356.003 315.803 406.659 292.898 437.377 244.983C462.305 206.1 463.157 156.595 450.1 117.036Z" fill="url(#paint12_linear_1_7)"/>
<path d="M450.1 117.036C443.847 98.0897 433.126 80.7844 419.588 66.1372C403.638 48.8804 383.775 35.7674 362.749 25.5553C344.86 16.8673 326.178 10.0107 306.871 5.74991C272.289 -1.88175 236.008 -1.7464 203.338 5.14589C167.82 12.6389 136.586 28.0095 116.833 47.2254C131.645 38.2253 152.305 30.926 167.027 27.2063C235.343 9.94493 310.57 28.6413 361.858 77.8279C372.17 87.7169 381.417 98.7823 388.914 110.971C419.511 160.713 416.616 223.248 392.761 260.13C375.039 287.529 337.09 313.232 301.682 312.954C356.003 315.803 406.659 292.898 437.377 244.983C462.305 206.1 463.157 156.595 450.1 117.036Z" fill="url(#paint13_linear_1_7)"/>
</g>
<defs>
<radialGradient id="paint0_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(447.072 94.7143) scale(567.377 568.723)">
<stop stop-color="#FFF44F"/>
<stop offset="0.294852" stop-color="#FF980E"/>
<stop offset="0.431521" stop-color="#FF5D36"/>
<stop offset="0.530208" stop-color="#FF3750"/>
<stop offset="0.749319" stop-color="#F5156C"/>
<stop offset="0.76479" stop-color="#F1136E"/>
<stop offset="0.880096" stop-color="#DA057A"/>
<stop offset="0.952784" stop-color="#D2007F"/>
</radialGradient>
<radialGradient id="paint1_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(41.434 118.242) scale(335.789 336.586)">
<stop stop-color="#B5007F"/>
<stop offset="1" stop-color="#F5156C" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint2_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(495.573 62.3537) scale(666.248 667.828)">
<stop stop-color="#FFDD00" stop-opacity="0.6"/>
<stop offset="0.0836672" stop-color="#FFD801" stop-opacity="0.524402"/>
<stop offset="0.182244" stop-color="#FECA05" stop-opacity="0.435332"/>
<stop offset="0.288366" stop-color="#FEB20C" stop-opacity="0.339445"/>
<stop offset="0.399791" stop-color="#FD9115" stop-opacity="0.238766"/>
<stop offset="0.515404" stop-color="#FB6621" stop-opacity="0.134303"/>
<stop offset="0.632872" stop-color="#F9332F" stop-opacity="0.028164"/>
<stop offset="0.664042" stop-color="#F92433" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint3_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(264.281 278.186) scale(859.512 861.552)">
<stop offset="0.152849" stop-color="#960E18"/>
<stop offset="0.20613" stop-color="#CC2335" stop-opacity="0.554139"/>
<stop offset="0.249478" stop-color="#F13148" stop-opacity="0.191404"/>
<stop offset="0.272351" stop-color="#FF3750" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint4_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(199.239 267.352) scale(859.512 861.552)">
<stop offset="0.112906" stop-color="#960E18"/>
<stop offset="0.189346" stop-color="#CC2335" stop-opacity="0.554139"/>
<stop offset="0.251535" stop-color="#F13148" stop-opacity="0.191404"/>
<stop offset="0.28435" stop-color="#FF3750" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint5_linear_1_7" x1="286.442" y1="48.5943" x2="434.03" y2="303.619" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFBC04"/>
<stop offset="0.259693" stop-color="#FFA202" stop-opacity="0.488604"/>
<stop offset="0.507812" stop-color="#FF8E00" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint6_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(435.167 75.4991) scale(532.55 533.814)">
<stop stop-color="#FF980E"/>
<stop offset="0.295012" stop-color="#FF7139"/>
<stop offset="0.484646" stop-color="#FF5B51"/>
<stop offset="0.626002" stop-color="#FF4F5E"/>
<stop offset="0.73652" stop-color="#FF4055"/>
<stop offset="0.842829" stop-color="#FF3750"/>
</radialGradient>
<radialGradient id="paint7_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(435.167 75.4991) scale(532.55 533.814)">
<stop offset="0.0840745" stop-color="#FFDE08"/>
<stop offset="0.208103" stop-color="#FFD609" stop-opacity="0.832008"/>
<stop offset="0.40327" stop-color="#FFBF0B" stop-opacity="0.567662"/>
<stop offset="0.643689" stop-color="#FF9B0F" stop-opacity="0.242024"/>
<stop offset="0.822376" stop-color="#FF7B12" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint8_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(312.131 241.565) rotate(75.719) scale(261.769 272.613)">
<stop offset="0.363381" stop-color="#FF3750"/>
<stop offset="0.411136" stop-color="#FF444B" stop-opacity="0.789478"/>
<stop offset="0.590223" stop-color="#FF7139" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint9_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(267.11 263.737) rotate(75.719) scale(261.769 261.454)">
<stop offset="0.215889" stop-color="#FF3750" stop-opacity="0.8"/>
<stop offset="0.270209" stop-color="#FF444B" stop-opacity="0.631583"/>
<stop offset="0.473917" stop-color="#FF7139" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint10_radial_1_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(541.45 15.2) scale(900.107 902.242)">
<stop offset="0.0535657" stop-color="#FFF44F"/>
<stop offset="0.457272" stop-color="#FF980E"/>
<stop offset="0.52105" stop-color="#FF8424"/>
<stop offset="0.587052" stop-color="#FF7634"/>
<stop offset="0.639343" stop-color="#FF7139"/>
</radialGradient>
<linearGradient id="paint11_linear_1_7" x1="368.882" y1="44.1075" x2="112.796" y2="486.612" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF44F" stop-opacity="0.8"/>
<stop offset="0.75" stop-color="#FFF44F" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint12_linear_1_7" x1="287.639" y1="314.472" x2="287.639" y2="3.17061" gradientUnits="userSpaceOnUse">
<stop stop-color="#3A8EE6"/>
<stop offset="0.235934" stop-color="#5C79F0"/>
<stop offset="0.629327" stop-color="#9059FF"/>
<stop offset="1" stop-color="#C139E6"/>
</linearGradient>
<linearGradient id="paint13_linear_1_7" x1="173.353" y1="1.74342" x2="425.949" y2="253.742" gradientUnits="userSpaceOnUse">
<stop offset="0.805429" stop-color="#9059FF" stop-opacity="0"/>
<stop offset="1" stop-color="#6E008B" stop-opacity="0.5"/>
</linearGradient>
<clipPath id="clip0_1_7">
<rect width="500" height="500" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1 @@
<svg height="512pt" viewBox="0 0 512 512" width="512pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(.43837115 .89879405 -.89879405 .43837115 0 0)">&gt;<stop offset="0" stop-color="#00a9ff"/><stop offset="1" stop-color="#05f"/></linearGradient><path d="m469.139 139.984-.016-.391c-.218-4.819-.363-9.919-.452-15.592-.409-27.666-22.402-50.55-50.071-52.097-57.69-3.219-102.319-22.031-140.45-59.198l-.326-.31c-12.437-11.404-31.199-11.404-43.64 0l-.326.31c-38.132 37.167-82.76 55.979-140.45 59.202-27.666 1.543-49.662 24.427-50.072 52.097-.084 5.635-.233 10.734-.452 15.588l-.023.907c-1.121 58.827-2.515 132.04 21.978 198.493 13.467 36.543 33.863 68.309 60.618 94.42 30.472 29.737 70.384 53.345 118.626 70.166 1.57.547 3.2.991 4.862 1.324 2.343.467 4.701.701 7.059.701s4.72-.234 7.059-.701c1.661-.333 3.304-.78 4.881-1.332 48.184-16.851 88.054-40.471 118.499-70.204 26.744-26.119 47.14-57.892 60.619-94.443 24.584-66.652 23.194-140.003 22.077-198.94z" fill="url(#a)"/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,4 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M348.185 1.98651C335.888 -0.838881 322.856 -0.18931 307.908 1.10769L61.7824 19.4822L61.5904 19.4969L61.459 19.5078C46.029 20.8632 32.37 27.1506 23.121 39.1599C14.4013 50.4814 12 63.8022 12 74.9404V348.014C12 367.649 19.4888 383.288 31.5785 399.623L31.7723 399.879L89.7367 476.12L89.8101 476.215C96.3914 484.701 104.432 492.043 115.735 496.225C126.186 500.092 137 500.293 146.936 499.813L147.02 499.809L147.177 499.8L147.253 499.796L433.252 482.287L433.303 482.284L433.436 482.275L433.517 482.27C448.807 481.169 464.24 476.661 475.101 464.16C485.703 451.959 487.694 436.935 487.694 425.047V117.831C487.694 108.11 485.351 98.6341 477.959 89.9565C473.589 84.8263 467.561 80.3871 462.902 76.9554L462.351 76.5496C461.668 76.0456 461.001 75.5537 460.339 75.0625L460.197 74.9568L459.961 74.7882L381.488 18.8742C371.335 11.4076 361.321 5.00502 348.185 1.98651Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M309.904 25.9322L63.6284 44.3172C43.7692 46.0606 36.8488 59.1944 36.8488 74.9395V348.013C36.8488 360.281 41.1626 370.768 51.537 384.783L109.43 460.93C118.938 473.19 127.581 475.814 145.739 474.936L431.736 457.428C455.927 455.686 462.846 444.299 462.846 425.046V117.83C462.846 107.878 458.961 105.003 447.509 96.5273C446.879 96.0604 446.225 95.5772 445.55 95.0754L366.935 39.0622C347.927 25.063 340.146 23.3022 309.904 25.9322ZM152.223 112.792C128.873 114.389 123.567 114.753 110.307 103.832L76.587 76.7003C73.148 73.1924 74.8725 68.8153 83.5074 67.9473L320.274 50.4414C340.142 48.6869 350.509 55.7002 358.291 61.8231L398.9 91.5849C400.628 92.4566 404.942 97.7016 399.756 97.7016L155.237 112.586L152.223 112.792ZM124.988 422.415V161.6C124.988 150.224 128.444 144.969 138.807 144.086L419.627 127.462C429.152 126.587 433.466 132.718 433.466 144.086V403.151C433.466 414.537 431.734 424.178 416.173 425.046L147.45 440.809C131.898 441.675 124.988 436.433 124.988 422.415ZM390.272 175.591C391.995 183.476 390.272 191.354 382.481 192.241L369.532 194.856V387.406C358.291 393.531 347.924 397.033 339.286 397.033C325.455 397.033 321.991 392.653 311.632 379.532L226.94 244.746V375.155L253.739 381.286C253.739 381.286 253.739 397.033 232.117 397.033L172.511 400.538C170.779 397.033 172.511 388.287 178.557 386.535L194.111 382.164V209.74L172.513 207.986C170.783 200.101 175.095 188.731 187.202 187.85L251.146 183.48L339.286 320.021V199.232L316.814 196.618C315.088 186.978 321.991 179.979 330.634 179.111L390.272 175.591Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,3 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M51.085 226.924C51.085 226.924 96.2921 159.994 186.556 153.069V128.787C86.5773 136.844 0 221.814 0 221.814C0 221.814 49.0359 364.059 186.556 377.083V351.273C85.6371 338.533 51.085 226.924 51.085 226.924ZM186.556 299.942V323.58C110.284 309.935 89.1125 230.375 89.1125 230.375C89.1125 230.375 125.734 189.666 186.556 183.064V209.002C186.509 209.002 186.477 208.988 186.439 208.988C154.516 205.143 129.579 235.068 129.579 235.068C129.579 235.068 143.556 285.445 186.556 299.942ZM186.556 84V128.787C189.491 128.561 192.425 128.37 195.376 128.269C309.041 124.425 383.101 221.814 383.101 221.814C383.101 221.814 298.041 325.604 209.422 325.604C201.301 325.604 193.697 324.848 186.556 323.578V351.273C192.662 352.051 198.994 352.508 205.601 352.508C288.067 352.508 347.703 310.247 405.45 260.229C415.024 267.923 454.22 286.642 462.278 294.836C407.372 340.964 279.411 378.147 206.865 378.147C199.872 378.147 193.157 377.722 186.556 377.083V416H500V84H186.556ZM186.556 183.064V153.069C189.46 152.866 192.387 152.711 195.376 152.616C277.112 150.04 330.737 223.098 330.737 223.098C330.737 223.098 272.818 303.817 210.716 303.817C201.779 303.817 193.767 302.375 186.556 299.942V209.002C218.376 212.86 224.778 226.964 243.908 258.965L286.456 222.965C286.456 222.965 255.397 182.091 203.04 182.091C197.349 182.089 191.903 182.49 186.556 183.064Z" fill="#76B900"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,5 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M446.258 230.173C434.83 295.328 381.676 344.578 311.926 344.578H267.645C258.614 344.578 249.514 352.94 248.072 362.188L228.68 485.284C227.555 492.294 224.272 494.623 217.172 494.623H145.945C138.743 494.623 137.039 492.214 138.118 485.114L146.298 399.986L60.8024 395.566C53.6116 395.566 51.0102 391.647 52.0325 384.467L110.366 14.5526C111.491 7.54283 115.853 4.53217 122.93 4.53217H270.871C342.087 4.53217 387.14 52.4756 392.65 114.643C435.023 143.273 454.834 181.366 446.269 230.162L446.258 230.173Z" fill="#001C64"/>
<path d="M167.972 262.157L146.309 400L132.609 486.48C132.354 488.148 132.462 489.85 132.924 491.472C133.386 493.094 134.192 494.598 135.287 495.881C136.382 497.163 137.741 498.195 139.27 498.906C140.8 499.617 142.464 499.99 144.151 500H219.376C222.81 499.996 226.13 498.767 228.739 496.535C231.348 494.303 233.075 491.213 233.61 487.821L253.411 362.168C253.949 358.778 255.677 355.691 258.286 353.461C260.895 351.231 264.213 350.004 267.645 350.001H311.926C345.668 349.957 378.285 337.859 403.896 315.889C429.507 293.919 446.428 263.521 451.608 230.176C459.276 181.244 434.659 136.698 392.525 114.692C392.43 119.905 391.974 125.106 391.162 130.256C385.962 163.584 369.035 193.96 343.428 215.913C317.822 237.867 285.219 249.955 251.491 250.001H182.195C178.766 250.002 175.449 251.227 172.842 253.456C170.235 255.684 168.508 258.77 167.972 262.157Z" fill="#0070E0"/>
<path d="M146.297 399.998H58.7005C57.0105 399.99 55.3422 399.617 53.8091 398.906C52.276 398.195 50.9144 397.161 49.8168 395.876C48.7193 394.591 47.9117 393.084 47.4491 391.458C46.9864 389.833 46.8797 388.126 47.1361 386.456L106.163 12.179C106.693 8.78702 108.418 5.6961 111.025 3.46315C113.633 1.23021 116.952 0.00205828 120.385 0H270.791C342.007 0 393.786 51.8289 392.57 114.621C373.615 104.841 352.565 99.8231 331.238 99.9995H205.846C202.412 100 199.091 101.226 196.48 103.456C193.869 105.687 192.139 108.775 191.601 112.167L167.972 262.155L146.297 399.998Z" fill="#003087"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 943.11 911.62"><script xmlns=""/>
<defs>
<style>
.cls-1 {
fill: #fff;
}
.cls-2 {
fill: #37474f;
}
.cls-3 {
fill: #46509e;
}
</style>
</defs>
<ellipse class="cls-3" cx="471.56" cy="454.28" rx="471.56" ry="454.28"/>
<g>
<g>
<ellipse class="cls-2" cx="471.56" cy="390.28" rx="233.66" ry="207"/>
<path class="cls-2" d="m705.22,848.95c-36.69,21.14-123.09,64.33-240.64,62.57-109.54-1.63-190.04-41.45-226.68-62.57v-454.19h467.33v454.19Z"/>
</g>
<path class="cls-1" d="m658.81,397.7v475.8c-36.98,15.7-98.93,36.54-177.98,38.04-88.67,1.69-157.75-21.73-196.2-38.04v-475.8c0-95.55,83.77-173.02,187.09-173.02s187.09,77.47,187.09,173.02Z"/>
<polygon class="cls-3" points="565.02 431.68 471.56 514.49 378.09 431.68 565.02 431.68"/>
<ellipse class="cls-2" cx="378.09" cy="369.58" rx="23.37" ry="20.7"/>
<ellipse class="cls-2" cx="565.02" cy="369.58" rx="23.37" ry="20.7"/>
<path class="cls-2" d="m658.49,400.63c0-40.04-36.59-72.45-81.78-72.45s-81.78,32.41-81.78,72.45c0,11.14,2.81,21.65,7.9,31.05h-62.54c5.1-9.4,7.9-19.91,7.9-31.05,0-40.04-36.59-72.45-81.78-72.45s-81.78,32.41-81.78,72.45l-46.73-10.35c0-114.32,104.63-207,233.66-207s233.66,92.69,233.66,207l-46.73,10.35Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,14 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M52 369.795V500H143.481V375.43C143.481 363.31 148.3 351.686 156.878 343.116C165.456 334.547 177.09 329.732 189.222 329.732H283.02C326.779 329.719 368.74 312.345 399.678 281.429C430.615 250.513 447.997 208.589 448 164.872C448 121.15 430.616 79.2177 399.673 48.2988C368.729 17.38 326.759 0.00664019 282.995 0H52V162.756H143.481V86.023H276.83C297.535 86.023 317.393 94.2386 332.035 108.863C346.678 123.487 354.909 143.323 354.915 164.009C354.915 184.698 346.689 204.541 332.044 219.17C317.401 233.8 297.539 242.019 276.83 242.019H179.885C163.088 242.011 146.453 245.31 130.933 251.728C115.413 258.148 101.311 267.559 89.434 279.426C77.557 291.293 68.1375 305.383 61.7143 320.889C55.2912 336.395 51.9901 353.014 52 369.795Z" fill="url(#paint0_radial_122_119)"/>
<path d="M189.196 329.731C152.81 329.735 117.916 344.178 92.1875 369.881C66.459 395.586 52.0033 430.446 52 466.798L52 500H143.481V375.429C143.481 363.313 148.297 351.694 156.869 343.125C165.442 334.556 177.069 329.738 189.196 329.731Z" fill="url(#paint1_linear_122_119)"/>
<defs>
<radialGradient id="paint0_radial_122_119" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(449.441 -69.4219) scale(503.735 503.255)">
<stop stop-color="#A995FF"/>
<stop offset="1" stop-color="#6652F5"/>
</radialGradient>
<linearGradient id="paint1_linear_122_119" x1="120.598" y1="475.374" x2="120.598" y2="284.048" gradientUnits="userSpaceOnUse">
<stop stop-color="#6D4BFD"/>
<stop offset="1" stop-color="#1C0554"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,6 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 388.755L126.571 249.665L0 110.571C13.9095 96.6616 33.3816 87.8523 54.7141 87.8523C77.4297 87.8523 97.3643 97.5937 111.274 112.89L181.281 189.854L235.992 249.665L181.281 309.942L111.274 386.902C97.3643 402.202 77.4297 411.94 54.7141 411.94C33.3816 411.94 13.9095 403.127 0 388.755ZM500 388.757L373.43 249.667L500 110.573C486.091 96.6633 466.619 87.8536 445.286 87.8536C422.571 87.8536 402.636 97.5956 388.726 112.892L318.719 189.856L264.008 249.667L318.719 309.943L388.726 386.904C402.636 402.204 422.571 411.942 445.286 411.942C466.619 411.942 486.091 403.128 500 388.757Z" fill="#E57000"/>
<g style="mix-blend-mode:difference">
<path fill-rule="evenodd" clip-rule="evenodd" d="M249.934 235.708L299.87 180.692L415.394 53.7358C402.7 41.0404 384.926 33 365.456 33C344.722 33 326.528 41.8913 313.83 55.8522L249.934 126.1L185.607 55.8522C172.491 41.4659 155.138 33 134.4 33C114.941 33 97.163 41.0404 84.4681 53.7358L199.996 180.692L249.934 235.708ZM249.937 263.615L299.873 318.631L415.398 445.588C402.703 458.283 384.929 466.323 365.459 466.323C344.725 466.323 326.531 457.432 313.834 443.471L249.937 373.224L185.61 443.471C172.494 457.857 155.141 466.323 134.403 466.323C114.944 466.323 97.1661 458.283 84.4713 445.588L200 318.631L249.937 263.615Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View 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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,13 @@
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" width="90" height="90">
<title>skiff</title>
<style>
.s0 { fill: #000000 }
</style>
<g id="Layer">
<g id="Layer">
<path id="Layer" fill-rule="evenodd" class="s0" d="m54.8 16.3q-1.8 0-3.6 0.3-1.7 0.4-3.4 1-1.7 0.7-3.2 1.7-1.5 0.9-2.8 2.2-1.3 1.2-2.3 2.7-1.1 1.4-1.8 3.1-0.8 1.6-1.2 3.3-0.5 1.8-0.6 3.6-0.1 1.8 0.2 3.5 0.2 1.8 0.7 3.5 0.6 1.8 1.5 3.3 0.8 1.6 2 3 1.1 1.4 2.5 2.5 1.4 1.2 2.9 2 1.6 0.9 3.3 1.4 1.7 0.6 3.5 0.8c0.6 0.1 1.2 0.2 1.8 0.2v0.9q-0.1 1.3-0.3 2.5c0 0.2-0.1 0.4-0.1 0.6-0.1 0.4-0.2 0.9-0.3 1.3-0.1 0.2-0.3 0.7-0.3 0.8l-0.2 0.6q-0.3 0.8-0.8 1.6-0.4 0.9-0.9 1.7-0.5 0.7-1 1.5-0.6 0.7-1.3 1.4-0.6 0.7-1.3 1.3-0.7 0.6-1.5 1.1-0.7 0.5-1.5 1-0.8 0.4-1.7 0.8c-2.1 0.9-4.4 1.4-6.8 1.5q-1.4 0-2.8-0.3l-0.8-0.1-0.9-0.2c-0.3-0.1-0.6-0.2-0.9-0.2-0.5-0.2-1.1-0.4-1.7-0.6-0.2-0.1-0.5-0.3-0.8-0.4l-0.7-0.4c-0.1 0-0.2-0.1-0.5-0.2-0.2-0.2-0.7-0.4-0.9-0.6l-0.3-0.2-0.2-0.1c-0.3-0.2-0.6-0.5-0.9-0.7l-0.2-0.2-0.2-0.1-0.4-0.4c-0.3-0.2-0.6-0.6-0.8-0.8l-1.2-1.2-1.1-1.2-0.7-0.9c-0.2-0.3-0.5-0.7-0.6-0.9-0.5-0.6-1-1.5-1.4-2.2q-1.4-2.4-2.4-5.1-0.9-2.7-1.4-5.5-0.5-2.8-0.5-5.7 0-2.8 0.5-5.6v-0.3c0.1-0.4 0.3-1.3 0.4-1.7 0.2-0.6 0.3-1.2 0.5-1.8 0.1-0.4 0.3-1 0.4-1.1 0-0.1 0.5-1.2 0.5-1.3l0.5-1.3c0.2-0.3 0.6-1.3 0.7-1.5 0.2-0.3 0.7-1.3 0.8-1.4 0.1-0.1 0.3-0.4 0.4-0.6 0.1-0.1 0.2-0.4 0.4-0.7 0.2-0.3 0.7-1.1 1-1.4l0.8-1.1c0.2-0.3 0.7-0.9 1.1-1.3 0.4-0.3 0.9-0.9 1.2-1.2 0.2-0.3 0.9-0.9 1.1-1.2 0.3-0.2 1-0.9 1.3-1.1q1.6-1.3 3.4-2.4 1.7-1.1 3.6-1.9 1.9-0.9 3.9-1.5 1.9-0.6 4-1 2-0.3 4.1-0.4 2.1-0.1 4.1 0.1 2.1 0.2 4.1 0.7 2 0.4 3.9 1.2 0.8 0.2 1.6 0.6 0.8 0.3 1.5 0.7 0.8 0.4 1.5 0.8 0.8 0.4 1.5 0.8c-2.5-1.1-5.3-1.7-8.1-1.6zm-22.3 50.8q2.3 0.9 4.7 1.1 2.5 0.2 4.9-0.3 2.5-0.5 4.6-1.7c-2.9 1.3-6.1 1.8-9.2 1.3q-1.1-0.2-2.3-0.5-1.1-0.4-2.2-0.8-1.1-0.5-2-1.2-1-0.6-1.9-1.4-0.3-0.2-0.5-0.5-0.2-0.2-0.5-0.4-0.2-0.3-0.4-0.5-0.3-0.3-0.5-0.5l-0.1-0.1-0.1-0.2-0.2-0.2q-0.8-1-1.6-2.1-0.7-1-1.3-2.1-0.6-1.1-1.2-2.2-0.5-1.2-0.9-2.4-1.1-3-1.5-6.1-0.4-3.1-0.1-6.2 0.3-3.2 1.2-6.2 1-3 2.6-5.7 0.7-1.4 1.6-2.6 1-1.3 2-2.5 1.1-1.1 2.2-2.2 1.2-1 2.5-1.9 1.2-0.9 2.6-1.7 1.4-0.7 2.8-1.3 1.4-0.6 2.9-1.1 1.5-0.4 3.1-0.7l1.3-0.2 1.4-0.2 1.3-0.1h-2.7l-1.4 0.1c-3.7 0.4-7.3 1.6-10.6 3.4q-1.5 0.9-2.9 1.9c-0.2 0.2-0.6 0.5-0.9 0.7q-1.1 0.9-2.2 2-1.1 1-2 2.2-1 1.2-1.8 2.4-0.8 1.3-1.5 2.6-1.4 2.7-2.2 5.6-0.8 2.9-1 5.9-0.3 3 0.1 6 0.4 3 1.5 5.9 0.4 1.4 1.1 2.7 0.6 1.4 1.4 2.7 0.8 1.3 1.7 2.5 0.9 1.2 1.9 2.3 0.3 0.2 0.5 0.5 0.3 0.3 0.5 0.5 0.3 0.2 0.5 0.5 0.3 0.2 0.6 0.4 1.9 1.6 4.2 2.6zm17.2-6.4c-2.9 1.5-6.1 2-9.2 1.4q-1.1-0.2-2.3-0.6-1.1-0.4-2.1-1-1-0.6-1.9-1.3-0.9-0.8-1.7-1.7c-0.4-0.4-0.8-0.9-1.2-1.4-0.2-0.2-0.5-0.7-0.7-0.9q-1-1.4-1.8-2.9-0.8-1.5-1.4-3-0.6-1.6-0.9-3.2-0.4-1.6-0.6-3.3-0.2-1.7-0.1-3.3 0-1.7 0.3-3.4 0.3-1.6 0.8-3.2 0.5-1.6 1.1-3.2 0.7-1.4 1.5-2.7 0.8-1.4 1.8-2.6 1-1.2 2.1-2.3 1.2-1.1 2.4-2.1 1.2-0.9 2.6-1.7 1.3-0.8 2.8-1.4 1.4-0.6 2.9-1.1 1.5-0.4 3.1-0.7 0.5-0.1 1-0.1 0.6-0.1 1.1-0.2 0.6 0 1.1 0 0.5-0.1 1.1-0.1-1.4-0.1-2.8-0.1h-1c-0.3 0-0.9 0.1-1.2 0.1q-0.8 0.1-1.7 0.3-0.8 0.1-1.6 0.3-0.8 0.2-1.6 0.5-0.8 0.2-1.5 0.5c-0.2 0.1-0.7 0.3-0.9 0.4-0.2 0.1-0.4 0.2-0.6 0.3-0.5 0.2-1.2 0.6-1.7 0.9-0.5 0.2-1.1 0.7-1.6 1q-0.3 0.2-0.7 0.4-0.3 0.3-0.6 0.5-0.3 0.3-0.6 0.5-0.3 0.3-0.6 0.6-1 0.8-1.9 1.8-0.8 0.9-1.6 2-0.8 1-1.5 2.1-0.6 1.1-1.2 2.3-1.1 2.3-1.7 4.8-0.6 2.6-0.8 5.2-0.1 2.6 0.3 5.1 0.4 2.6 1.3 5 0.5 1.3 1 2.4 0.6 1.2 1.3 2.3 0.7 1.1 1.5 2.1 0.7 1 1.6 2l0.8 0.8 0.1 0.1 0.2 0.2c4.7 4.3 12.2 5.4 17.5 1.6zm-14.3-10.1q-0.7-1.1-1.3-2.2-0.6-1.1-1.1-2.3-0.5-1.2-0.8-2.5-0.3-1.2-0.5-2.5-0.2-1.3-0.2-2.6-0.1-1.2 0.1-2.5 0.1-1.3 0.3-2.6 0.3-1.2 0.7-2.5 0.4-1.2 1-2.3 0.5-1.2 1.2-2.3 0.6-1.1 1.4-2.1 0.8-1 1.7-1.9 1-0.9 2-1.7 1-0.8 2.1-1.5 1-0.7 2.2-1.2 1.2-0.5 2.4-0.9 0.7-0.3 1.5-0.5 0.7-0.2 1.5-0.3 0.7-0.2 1.5-0.3 0.7-0.1 1.5-0.1h2.4c-0.4-0.1-0.9-0.2-1.3-0.2l-0.8-0.1h-2.2q-1 0.1-1.9 0.2-1 0.1-1.9 0.3-1 0.3-1.9 0.6-0.9 0.3-1.8 0.6c-0.4 0.2-0.7 0.3-1.3 0.6-0.5 0.3-1.1 0.7-1.6 1-0.3 0.2-0.7 0.4-1 0.6q-0.9 0.7-1.8 1.5-0.9 0.8-1.7 1.7-0.8 0.9-1.6 1.8-0.7 1-1.3 2-1.2 2.1-1.9 4.4-0.8 2.3-1 4.7-0.3 2.4 0 4.8 0.2 2.4 1 4.6 0.4 1.2 0.9 2.3 0.5 1.1 1.1 2.1 0.6 1 1.3 2 0.7 1 1.5 1.8 0.5 0.6 1 1 0.5 0.5 1.1 0.9 0.5 0.5 1.1 0.8 0.6 0.4 1.3 0.7 1.2 0.7 2.5 1 1.4 0.3 2.8 0.4 1.3 0 2.7-0.2 1.3-0.3 2.6-0.9c-2 0.7-4.2 0.8-6.3 0.3q-0.7-0.1-1.5-0.4-0.7-0.2-1.5-0.5-0.7-0.4-1.4-0.8-0.6-0.4-1.2-0.9-0.6-0.5-1-0.9-0.5-0.5-0.9-1-0.5-0.4-0.9-1-0.4-0.5-0.8-1z"/>
<path id="Layer" class="s0" d="m37.4 35.8l-0.7-0.1v0.1q0.8 0 1.5 0.1z"/>
<path id="Layer" fill-rule="evenodd" class="s0" d="m62 72.2q-1.7 1.1-3.6 2-1.9 0.8-3.9 1.4-2 0.6-4 1-2.1 0.3-4.1 0.4-2.1 0.1-4.2-0.1-2-0.2-4.1-0.6-2-0.5-3.9-1.2-0.8-0.3-1.6-0.6-0.8-0.3-1.5-0.7-0.8-0.4-1.5-0.8-0.7-0.4-1.5-0.9 2.2 1 4.5 1.4 2.3 0.4 4.7 0.2 2.3-0.1 4.6-0.9 2.2-0.7 4.2-2 1-0.6 1.9-1.3 0.9-0.8 1.7-1.6 0.8-0.9 1.5-1.8 0.8-0.9 1.3-2 0.6-1 1.1-2.1 0.5-1 0.8-2.2 0.3-1.1 0.5-2.3 0.2-1.1 0.3-2.3 0-1-0.1-1.9 0-0.9-0.2-1.9-0.2-0.9-0.4-1.8-0.2-0.9-0.6-1.8-0.3-0.8-0.7-1.7-0.4-0.8-0.9-1.6-0.5-0.8-1.1-1.5-0.6-0.8-1.2-1.5-0.7-0.6-1.4-1.3-0.7-0.6-1.5-1.1-0.7-0.5-1.5-1-0.9-0.4-1.7-0.8c-2.3-1-4.7-1.5-7.2-1.6v-1q0-1.3 0.3-2.5c0-0.2 0.1-0.4 0.1-0.6 0.1-0.4 0.2-0.9 0.3-1.3 0.1-0.2 0.2-0.7 0.3-0.8l0.2-0.6q0.3-0.8 0.7-1.7 0.4-0.8 0.9-1.6 0.5-0.8 1.1-1.5 0.6-0.7 1.2-1.4 0.7-0.7 1.4-1.3 0.7-0.6 1.4-1.1 0.8-0.5 1.6-1 0.8-0.4 1.7-0.8c2.1-0.9 4.4-1.4 6.7-1.5q0.4 0 0.8 0 0.3 0.1 0.7 0.1 0.3 0 0.7 0.1 0.3 0 0.7 0l0.8 0.2 0.8 0.2 1 0.2c0.5 0.2 1.1 0.4 1.7 0.6l0.7 0.4 0.8 0.4c0.1 0 0.2 0.1 0.4 0.2 0.3 0.2 0.7 0.4 1 0.6l0.2 0.2 0.3 0.1c0.2 0.2 0.6 0.5 0.8 0.7l0.3 0.2h0.1l0.1 0.1 0.4 0.4c0.2 0.2 0.6 0.6 0.8 0.8 0.4 0.3 0.9 0.9 1.2 1.1 0.2 0.3 0.8 1.1 1.1 1.3l0.6 0.9q0.1 0.1 0.2 0.3 0.1 0.1 0.2 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.2 0.2c0.4 0.7 1 1.5 1.4 2.2q1.4 2.4 2.3 5.1 1 2.7 1.5 5.5 0.5 2.8 0.5 5.7 0 2.8-0.6 5.6v0.3c0 0.4-0.2 1.3-0.3 1.7-0.2 0.6-0.4 1.2-0.6 1.8 0 0.3-0.2 1-0.3 1.1-0.1 0.1-0.5 1.2-0.5 1.3-0.2 0.4-0.4 1-0.5 1.3-0.2 0.3-0.7 1.3-0.8 1.5-0.1 0.3-0.7 1.3-0.7 1.4-0.1 0.1-0.3 0.5-0.4 0.6l-0.4 0.7c-0.2 0.3-0.8 1.1-1 1.4l-0.8 1.1c-0.3 0.3-0.8 1-1.1 1.3l-2.4 2.4c-0.2 0.2-1 0.9-1.2 1.1q-1.6 1.3-3.4 2.4zm-3.4-49.3q-2.3-0.9-4.8-1.2-2.5-0.2-4.9 0.4-2.4 0.5-4.6 1.7 1.2-0.5 2.5-0.9 1.3-0.3 2.7-0.5 1.3-0.1 2.6 0 1.4 0.1 2.7 0.4 1.3 0.3 2.6 0.8 1.2 0.5 2.4 1.2 1.1 0.7 2.1 1.6 1 0.9 1.9 2l0.1 0.1 0.1 0.1 0.2 0.3c0.3 0.3 0.6 0.7 0.9 1q1.5 2.1 2.6 4.3 1.2 2.3 1.9 4.7 0.8 2.4 1.1 4.9 0.3 2.5 0.1 5.1-0.1 2.5-0.7 4.9-0.5 2.5-1.5 4.8-1 2.4-2.4 4.5-1.3 2.1-3.1 4-1.9 2-4.2 3.7-2.2 1.6-4.8 2.8-2.5 1.2-5.3 1.9-2.7 0.7-5.5 0.8 1.7 0.1 3.5 0 1.7-0.2 3.4-0.5 1.7-0.4 3.4-1 1.6-0.6 3.2-1.3l1.2-0.7q0.4-0.2 0.8-0.4 0.4-0.3 0.7-0.5 0.4-0.3 0.8-0.5 0.3-0.3 0.7-0.5l0.7-0.6 0.1-0.1 0.3-0.2 0.5-0.5c0.4-0.2 0.8-0.6 1.1-0.9q2.1-2 3.7-4.3 1.6-2.4 2.8-5 1.2-2.6 1.8-5.4 0.6-2.8 0.7-5.7 0.1-2.8-0.4-5.7-0.5-2.8-1.5-5.5-1-2.6-2.5-5.1-1.5-2.4-3.4-4.5-0.3-0.3-0.5-0.5-0.3-0.3-0.5-0.5-0.3-0.3-0.6-0.5-0.2-0.3-0.5-0.5-1.9-1.6-4.2-2.5zm-0.5 7.3q0 0 0 0 0 0 0 0 0 0 0 0zm0 0c0 0 0 0 0 0-4.6-3.8-11.8-4.5-16.7-0.9q1-0.6 2.1-0.9 1.1-0.4 2.2-0.6 1.2-0.2 2.3-0.2 1.2 0 2.3 0.2 1.2 0.2 2.3 0.6 1.1 0.4 2.1 1 1 0.5 1.9 1.2 0.9 0.8 1.7 1.6c0.3 0.4 0.8 0.9 1 1.2 0.3 0.3 0.6 0.6 0.8 0.9q1 1.4 1.8 2.9 0.9 1.5 1.5 3.1 0.6 1.6 1 3.2 0.5 1.7 0.6 3.4 0.2 1.7 0.2 3.4 0 1.7-0.3 3.4-0.3 1.6-0.8 3.3-0.4 1.6-1.1 3.2-0.7 1.4-1.5 2.7-0.8 1.3-1.7 2.5-1 1.2-2 2.3-1.1 1.1-2.3 2-1.2 0.9-2.5 1.7-1.3 0.8-2.7 1.5-1.4 0.6-2.8 1.1-1.5 0.5-3 0.8-0.6 0.1-1.2 0.2-0.6 0.1-1.2 0.1-0.6 0.1-1.3 0.1-0.6 0.1-1.2 0.1 1.3 0.1 2.5 0.1 1.3 0 2.5-0.1 1.3-0.2 2.5-0.4 1.3-0.3 2.5-0.7c0.3-0.1 0.8-0.3 1.1-0.4l0.3-0.1 0.2-0.1 0.1-0.1 0.6-0.2q1.4-0.7 2.8-1.5 1.3-0.8 2.6-1.8 1.2-0.9 2.3-2.1 1.1-1.1 2-2.3 1-1.3 1.8-2.6 0.8-1.4 1.5-2.8 0.6-1.5 1-3 0.5-1.5 0.8-3 0.2-1.6 0.3-3.2 0.1-1.5 0-3.1-0.1-1.6-0.4-3.1-0.3-1.6-0.8-3.1-0.5-1.5-1.2-2.9-0.6-1.4-1.5-2.8-0.8-1.3-1.8-2.6-1-1.2-2.1-2.3c-0.4-0.3-0.7-0.6-1.1-0.9zm-12.6 42.4c-3 1.2-6.2 1.7-9.4 1.6q1.2 0.2 2.5 0.3 1.2 0.1 2.4 0 1.3-0.1 2.5-0.3 1.2-0.3 2.4-0.6 1.3-0.5 2.5-1 1.3-0.6 2.4-1.3 1.2-0.8 2.3-1.6 1-0.9 2-1.9 0.9-1 1.8-2.1 0.8-1.1 1.5-2.3 0.7-1.2 1.2-2.4 0.5-1.3 0.9-2.6 0.4-1.3 0.6-2.7 0.2-1.4 0.3-2.8 0-1.3-0.1-2.7-0.1-1.4-0.4-2.7-0.3-1.4-0.8-2.7-0.4-1.3-1-2.5-0.6-1.3-1.4-2.4-0.7-1.2-1.6-2.2-0.4-0.5-0.8-0.9-0.4-0.4-0.8-0.8-0.4-0.4-0.8-0.7-0.4-0.4-0.9-0.7-1.3-1-2.9-1.6-1.6-0.6-3.2-0.8-1.7-0.2-3.4 0-1.6 0.3-3.2 1 0.8-0.3 1.6-0.4 0.8-0.1 1.6-0.2 0.7 0 1.5 0 0.8 0.1 1.6 0.3 0.8 0.1 1.5 0.4 0.8 0.2 1.5 0.5 0.7 0.4 1.4 0.8 0.7 0.4 1.3 0.9 0.3 0.3 0.6 0.5 0.3 0.3 0.5 0.6 0.3 0.2 0.6 0.5 0.2 0.3 0.5 0.6l0.6 0.9 0.7 0.8 0.5 0.9q1.1 1.7 1.9 3.6 0.7 1.9 1.1 4 0.4 2 0.4 4 0 2.1-0.3 4.1-0.4 2-1.1 3.9-0.8 1.9-1.8 3.7-1.1 1.7-2.5 3.3-1.4 1.5-3 2.7c-0.3 0.2-0.7 0.6-1.1 0.8l-1.1 0.7c-0.4 0.2-0.8 0.4-1.2 0.6l-0.9 0.5-1 0.4z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,4 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M464.522 368.578C387.094 331.097 374.754 273.228 374.204 268.935C373.54 263.736 372.786 259.648 378.522 254.359C384.054 249.249 408.594 234.06 415.403 229.308C426.657 221.439 431.614 213.582 427.96 203.925C425.405 197.243 419.184 194.727 412.631 194.727C410.563 194.733 408.503 194.964 406.486 195.417C394.12 198.099 382.112 204.295 375.162 205.969C374.327 206.184 373.47 206.3 372.607 206.313C368.903 206.313 367.498 204.666 367.855 200.207C368.724 186.691 370.563 160.312 368.43 135.669C365.505 101.765 354.569 84.9663 341.603 70.1093C335.331 62.9043 306.204 31.9512 249.996 31.9512C193.787 31.9512 164.699 62.9043 158.465 70.0199C145.46 84.8769 134.538 101.676 131.638 135.58C129.504 160.222 131.421 186.589 132.213 200.118C132.468 204.359 131.165 206.224 127.46 206.224C126.598 206.209 125.741 206.094 124.905 205.879C117.969 204.206 105.961 198.01 93.5946 195.327C91.5774 194.875 89.5171 194.644 87.4499 194.637C80.8709 194.637 74.6752 197.192 72.1202 203.835C68.4667 213.493 73.3977 221.349 84.6906 229.219C91.4995 233.971 116.04 249.147 121.571 254.27C127.294 259.559 126.553 263.646 125.889 268.846C125.34 273.202 112.987 331.071 35.5717 368.489C31.0367 370.686 23.3208 375.336 36.9259 382.847C58.2852 394.651 72.5035 393.387 83.5536 400.502C92.9303 406.545 87.3861 419.575 94.2078 424.276C102.588 430.063 127.358 423.867 159.359 434.432C186.186 443.272 202.486 468.247 250.059 468.247C297.633 468.247 314.406 443.157 340.76 434.432C372.697 423.867 397.518 430.063 405.911 424.276C412.72 419.575 407.189 406.545 416.565 400.502C427.615 393.387 441.821 394.651 463.193 382.847C476.773 375.425 469.057 370.775 464.522 368.578Z" fill="white"/>
<path d="M498.208 364.171C494.734 354.717 488.116 349.659 480.579 345.469C479.161 344.638 477.858 343.974 476.747 343.463C474.499 342.3 472.199 341.176 469.912 339.988C446.42 327.533 428.075 311.82 415.352 293.194C411.738 287.951 408.604 282.393 405.988 276.587C404.902 273.483 404.953 271.72 405.732 270.11C406.505 268.87 407.527 267.805 408.734 266.981C412.771 264.311 416.936 261.602 419.759 259.776C424.792 256.518 428.778 253.938 431.346 252.111C440.99 245.366 447.736 238.199 451.951 230.189C454.893 224.656 456.608 218.553 456.98 212.297C457.353 206.041 456.374 199.779 454.11 193.935C447.723 177.123 431.844 166.686 412.605 166.686C408.547 166.682 404.5 167.111 400.533 167.964C399.473 168.194 398.412 168.436 397.378 168.705C397.556 157.207 397.301 145.071 396.279 133.127C392.651 91.1365 377.947 69.1256 362.618 51.5732C352.801 40.574 341.238 31.2685 328.394 24.0308C305.131 10.7451 278.751 4.00006 249.995 4.00006C221.24 4.00006 194.988 10.7451 171.699 24.0308C158.824 31.2707 147.238 40.5949 137.412 51.6243C122.082 69.1767 107.378 91.2259 103.75 133.178C102.728 145.123 102.473 157.322 102.639 168.756C101.604 168.487 100.557 168.245 99.4964 168.015C95.5291 167.162 91.4823 166.734 87.4243 166.737C68.1728 166.737 52.2682 177.174 45.9064 193.986C43.6324 199.832 42.6437 206.099 43.0074 212.362C43.3711 218.624 45.0788 224.735 48.0142 230.279C52.2427 238.289 58.9877 245.455 68.6327 252.2C71.1876 253.989 75.1861 256.569 80.2193 259.865C82.9404 261.628 86.9133 264.209 90.8096 266.789C92.1728 267.67 93.3315 268.833 94.2077 270.2C95.0253 271.873 95.0508 273.675 93.8372 276.996C91.2559 282.679 88.1736 288.122 84.6266 293.258C72.184 311.462 54.3761 326.894 31.637 339.247C19.5905 345.635 7.07124 349.901 1.7825 364.273C-2.20322 375.119 0.402827 387.459 10.5332 397.858C14.2511 401.739 18.5634 405.003 23.3079 407.528C33.1801 412.954 43.6777 417.153 54.5677 420.035C56.815 420.614 58.9485 421.569 60.8784 422.858C64.5703 426.09 64.0465 430.957 68.9648 438.085C71.4337 441.769 74.5707 444.958 78.2137 447.488C88.5357 454.616 100.135 455.063 112.424 455.536C123.526 455.957 136.109 456.443 150.48 461.182C156.433 463.149 162.616 466.956 169.783 471.402C186.991 481.979 210.547 496.453 249.97 496.453C289.393 496.453 313.115 481.903 330.451 471.287C337.566 466.918 343.711 463.149 349.498 461.233C363.869 456.481 376.453 456.008 387.554 455.587C399.843 455.114 411.443 454.667 421.765 447.539C426.079 444.53 429.674 440.604 432.291 436.041C435.83 430.024 435.74 425.822 439.062 422.883C440.872 421.656 442.876 420.74 444.989 420.175C456.028 417.285 466.668 413.046 476.67 407.554C481.711 404.85 486.249 401.297 490.084 397.053L490.212 396.9C499.716 386.731 502.105 374.748 498.208 364.171ZM463.167 383.001C441.795 394.805 427.59 393.54 416.54 400.655C407.15 406.698 412.707 419.728 405.886 424.429C397.505 430.216 372.735 424.02 340.734 434.585C314.342 443.31 297.505 468.4 250.034 468.4C202.563 468.4 186.122 443.361 159.295 434.521C127.358 423.956 102.537 430.152 94.1438 424.365C87.3349 419.664 92.8663 406.634 83.4897 400.592C72.4268 393.476 58.2213 394.741 36.8619 383.001C23.2568 375.489 30.9728 370.839 35.5078 368.642C112.923 331.161 125.276 273.291 125.825 268.999C126.489 263.8 127.23 259.712 121.507 254.423C115.976 249.313 91.4356 234.124 84.6266 229.372C73.3593 221.503 68.4027 213.646 72.0563 203.988C74.6112 197.307 80.8453 194.791 87.386 194.791C89.4531 194.797 91.5135 195.028 93.5306 195.481C105.897 198.163 117.905 204.359 124.841 206.032C125.677 206.247 126.534 206.363 127.396 206.377C131.101 206.377 132.404 204.512 132.149 200.271C131.357 186.743 129.44 160.376 131.574 135.733C134.499 101.829 145.422 85.0302 158.401 70.1732C164.635 63.0321 193.927 32.0789 249.944 32.0789C305.962 32.0789 335.331 62.9043 341.565 70.0199C354.557 84.8769 365.492 101.676 368.392 135.58C370.525 160.222 368.686 186.602 367.817 200.118C367.523 204.576 368.864 206.224 372.569 206.224C373.431 206.21 374.289 206.094 375.124 205.879C382.073 204.206 394.082 198.01 406.448 195.327C408.465 194.875 410.525 194.644 412.592 194.637C419.171 194.637 425.367 197.192 427.922 203.835C431.576 213.493 426.644 221.349 415.364 229.219C408.555 233.971 384.015 249.147 378.484 254.27C372.748 259.559 373.502 263.646 374.166 268.846C374.715 273.202 387.056 331.071 464.483 368.489C469.057 370.775 476.773 375.425 463.167 383.001Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,5 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<g style="mix-blend-mode:difference">
<path d="M296.617 211.716L479.03 0H435.804L277.414 183.83L150.909 0H5L196.301 277.983L5 500H48.2286L215.492 305.869L349.091 500H495L296.606 211.716H296.617ZM237.409 280.432L218.026 252.752L63.8045 32.492H130.201L254.66 210.249L274.043 237.929L435.824 468.986H369.428L237.409 280.443V280.432Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 458 B

View File

@@ -38,6 +38,8 @@ PODS:
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- file_saver (0.0.1):
- Flutter
- fk_user_agent (2.0.0):
- Flutter
- Flutter (1.0.0)
@@ -110,6 +112,7 @@ DEPENDENCIES:
- connectivity (from `.symlinks/plugins/connectivity/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- file_saver (from `.symlinks/plugins/file_saver/ios`)
- fk_user_agent (from `.symlinks/plugins/fk_user_agent/ios`)
- Flutter (from `Flutter`)
- flutter_email_sender (from `.symlinks/plugins/flutter_email_sender/ios`)
@@ -153,6 +156,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/device_info_plus/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
file_saver:
:path: ".symlinks/plugins/file_saver/ios"
fk_user_agent:
:path: ".symlinks/plugins/fk_user_agent/ios"
Flutter:
@@ -202,6 +207,7 @@ SPEC CHECKSUMS:
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
@@ -225,7 +231,7 @@ SPEC CHECKSUMS:
Sentry: e3203780941722a1fcfee99e351de14244c7f806
sentry_flutter: 8f0ffd53088e6a4d50c095852c5cad9e4405025c
SentryPrivate: 5e3683390f66611fc7c6215e27645873adb55d13
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f

View File

@@ -45,7 +45,7 @@ class Configuration {
final List<String> onlineSecureKeys = [
keyKey,
secretKeyKey,
authSecretKeyKey
authSecretKeyKey,
];
final kTempFolderDeletionTimeBuffer = const Duration(days: 1).inMicroseconds;

View File

@@ -41,6 +41,8 @@ class InvalidStateError extends AssertionError {
class KeyDerivationError extends Error {}
class LoginKeyDerivationError extends Error {}
class SrpSetupNotCompleteError extends Error {}
class AuthenticatorKeyNotFound extends Error {}

View File

@@ -122,7 +122,7 @@ class _CredentialBuilder {
return headers
..addAll(
<String, String>{
'X-Sentry-Auth': '$_authHeader, sentry_timestamp=$timestamp'
'X-Sentry-Auth': '$_authHeader, sentry_timestamp=$timestamp',
},
);
}

1
lib/l10n/arb/app_ar.arb Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -1,5 +1,6 @@
{
"account": "Konto",
"unlock": "Entsperren",
"recoveryKey": "Wiederherstellungsschlüssel",
"counterAppBarTitle": "Zähler",
"@counterAppBarTitle": {
@@ -9,6 +10,7 @@
"onBoardingGetStarted": "Los geht's",
"setupFirstAccount": "Ihr erstes Konto einrichten",
"importScanQrCode": "Scannen eines QR-Codes",
"qrCode": "QR-Code",
"importEnterSetupKey": "Einen Setup-Schlüssel eingeben",
"importAccountPageTitle": "Kontodaten eingeben",
"secretCanNotBeEmpty": "Geheimnis darf nicht leer sein",
@@ -57,6 +59,9 @@
}
},
"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...",
@@ -72,19 +77,33 @@
"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",
"importInstruction": "Bitte wählen sie eine Datei die Codes in folgendem Format beinhaltet",
"importCodeDelimiterInfo": "Codes können in einer neuen Zeile stehen oder durch Kommata getrennt sein",
"selectFile": "Datei auswählen",
"emailVerificationToggle": "E-Mail-Verifizierung",
"authToChangeEmailVerificationSetting": "Bitte Authentifizieren um die E-Mail Bestätigung zu ändern",
"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",
"no": "Nein",
"email": "E-Mail",
"support": "Unterstützung",
"general": "Allgemein",
"settings": "Einstellungen",
"copied": "Kopiert",
"pleaseTryAgain": "Bitte versuchen Sie es erneut",
@@ -94,6 +113,17 @@
"enterYourPasswordHint": "Geben Sie Ihr Passwort ein",
"forgotPassword": "Passwort vergessen",
"oops": "Hopla",
"suggestFeatures": "Features vorschlagen",
"faq": "FAQ",
"faq_q_1": "Wie sicher ist ente Auth?",
"faq_a_1": "Alle Codes, die Sie über ente sichern, werden Ende-zu-Ende-verschlüsselt gespeichert. Das bedeutet, dass nur Sie auf Ihre Codes zugreifen können. Unsere Apps sind Open Source und unsere Kryptografie wurde extern überprüft.",
"faq_q_2": "Kann ich auf meine Codes auf dem Desktop zugreifen?",
"faq_a_2": "Sie können auf Ihre Codes im Web via auth.ente.io zugreifen.",
"faq_q_3": "Wie kann ich Codes löschen?",
"faq_a_3": "Sie können einen Code löschen, indem Sie auf dem Code nach links wischen.",
"faq_q_4": "Wie kann ich das Projekt unterstützen?",
"faq_a_4": "Sie können die Entwicklung dieses Projekts unterstützen, indem Sie unsere Fotos-App auf ente.io abonnieren.",
"faq_q_5": "Wie kann ich FaceID Sperre in ente Auth aktivieren",
"somethingWentWrongMessage": "Ein Fehler ist aufgetreten, bitte versuchen Sie es erneut",
"leaveFamily": "Familie verlassen",
"leaveFamilyMessage": "Sind Sie sicher, dass Sie den Familien-Plan verlassen wollen?",
@@ -126,8 +156,6 @@
"yesSendFeedbackAction": "Ja, Feedback senden",
"noDeleteAccountAction": "Nein, Konto löschen",
"initiateAccountDeleteTitle": "Bitte authentifizieren Sie sich, um die Kontolöschung einzuleiten",
"confirmAccountDeleteTitle": "Sind Sie sicher, dass Sie Ihr ente Konto löschen wollen?",
"confirmAccountDeleteMessage": "Ihre hochgeladenen Daten werden in allen Anwendungen (sowohl Fotos als auch Authenticator) zur Löschung vorgesehen und Ihr Konto wird dauerhaft gelöscht.",
"sendEmail": "E-Mail senden",
"createNewAccount": "Neues Konto erstellen",
"weakStrength": "Schwach",
@@ -154,12 +182,14 @@
"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.",
"recoveryKeySaveDescription": "Wir speichern diesen Schlüssel nicht. Sichern sie dieses diesen Schlüssel bestehend aus 24 Wörtern an einem sicheren Platz.",
"doThisLater": "Auf später verschieben",
"saveKey": "Schlüssel speichern",
"back": "Zurück",
"createAccount": "Account erstellen",
"passwordStrength": "Passwortstärke: {passwordStrengthValue}",
"@passwordStrength": {
@@ -223,6 +253,10 @@
"privacy": "Datenschutz",
"terms": "Bestimmungen",
"checkForUpdates": "Auf Updates prüfen",
"downloadUpdate": "Herunterladen",
"criticalUpdateAvailable": "Kritische neue Aktualisierung ist verfügbar",
"updateAvailable": "Aktualisierung verfügbar",
"update": "Aktualisierung",
"checking": "Prüfe...",
"youAreOnTheLatestVersion": "Sie haben die aktuellste Version",
"warning": "Warnung",
@@ -267,5 +301,82 @@
"thisWillLogYouOutOfTheFollowingDevice": "Dadurch wirst du von folgendem Gerät abgemeldet:",
"terminateSession": "Sitzungen beenden?",
"terminate": "Beenden",
"thisDevice": "Dieses Gerät"
"thisDevice": "Dieses Gerät",
"toResetVerifyEmail": "Um Ihr Passwort zurückzusetzen, verifizieren Sie bitte zuerst Ihre E-Mail-Adresse.",
"thisEmailIsAlreadyInUse": "Diese E-Mail-Adresse wird bereits verwendet",
"verificationFailedPleaseTryAgain": "Verifizierung fehlgeschlagen, bitte versuchen Sie es erneut",
"yourVerificationCodeHasExpired": "Ihr Bestätigungscode ist abgelaufen",
"incorrectCode": "Falscher Code",
"sorryTheCodeYouveEnteredIsIncorrect": "Leider ist der eingegebene Code falsch",
"emailChangedTo": "E-Mail-Adresse geändert zu {newEmail}",
"authenticationFailedPleaseTryAgain": "Authentifizierung fehlgeschlagen, versuchen Sie es bitte erneut",
"authenticationSuccessful": "Authentifizierung erfolgreich!",
"twofactorAuthenticationSuccessfullyReset": "Zwei-Faktor-Authentifizierung (2FA) erfolgreich zurückgesetzt",
"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",
"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!"
}

View File

@@ -1,5 +1,6 @@
{
"account": "Account",
"unlock": "Unlock",
"recoveryKey": "Recovery key",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
@@ -70,7 +71,7 @@
"incorrectPasswordTitle": "Incorrect password",
"welcomeBack": "Welcome back!",
"madeWithLoveAtPrefix": "made with ❤️ at ",
"supportDevs": "Subscribe to <bold-green>ente</bold-green> to support this project",
"supportDevs": "Subscribe to <bold-green>ente</bold-green> to support us",
"supportDiscount": "Use coupon code \"AUTH\" to get 10% off first year",
"changeEmail": "Change email",
"changePassword": "Change password",
@@ -83,20 +84,25 @@
"importFromApp": "Import codes from {appName}",
"importGoogleAuthGuide": "Export your accounts from Google Authenticator to a QR code using the \"Transfer Accounts\" option. Then using another device, scan the QR code.\n\nTip: You can use your laptop's webcam to take a picture of the QR code.",
"importSelectJsonFile": "Select JSON file",
"importSelectAppExport": "Select {appName} export file",
"importEnteEncGuide": "Select the encrypted JSON file exported from ente",
"importRaivoGuide": "Use the \"Export OTPs to Zip archive\" option in Raivo's Settings.\n\nExtract the zip file and import the JSON file.",
"importBitwardenGuide": "Use the \"Export vault\" option within Bitwarden Tools and import the unencrypted JSON file.",
"importAegisGuide": "Use the \"Export the vault\" option in Aegis's Settings.\n\nIf your vault is encrypted, you will need to enter vault password to decrypt the vault.",
"import2FasGuide": "Use the \"Settings->Backup -Export\" option in 2FAS.\n\nIf your backup is encrypted, you will need to enter the password to decrypt the backup",
"exportCodes": "Export codes",
"importLabel": "Import",
"importInstruction": "Please select a file that contains a list of your codes in the following format",
"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",
"authToChangeYourPassword": "Please authenticate to change your password",
"authToViewSecrets": "Please authenticate to view your secrets",
"authToInitiateSignIn": "Please authenticate to initiate sign in for backup.",
"ok": "Ok",
"cancel": "Cancel",
"yes": "Yes",
@@ -126,6 +132,7 @@
"faq_q_5": "How can I enable FaceID lock in ente Auth",
"faq_a_5": "You can enable FaceID lock under Settings → Security → Lockscreen.",
"somethingWentWrongMessage": "Something went wrong, please try again",
"leaveFamily": "Leave family",
"leaveFamilyMessage": "Are you sure that you want to leave the family plan?",
"inFamilyPlanMessage": "You are on a family plan!",
@@ -157,8 +164,6 @@
"yesSendFeedbackAction": "Yes, send feedback",
"noDeleteAccountAction": "No, delete account",
"initiateAccountDeleteTitle": "Please authenticate to initiate account deletion",
"confirmAccountDeleteTitle": "Are you sure you want to delete your ente account?",
"confirmAccountDeleteMessage": "Your uploaded data, across all apps (Photos and Authenticator both), will be scheduled for deletion, and your account will be permanently deleted.",
"sendEmail": "Send email",
"createNewAccount": "Create new account",
"weakStrength": "Weak",
@@ -331,5 +336,73 @@
"offlineModeWarning": "You have chosen to proceed without backups. Please take manual backups to make sure your codes are safe.",
"showLargeIcons": "Show large icons",
"shouldHideCode": "Hide codes",
"focusOnSearchBar": "Focus search on app start"
"doubleTapToViewHiddenCode" : "You can double tap on an entry to view code",
"focusOnSearchBar": "Focus search on app start",
"confirmUpdatingkey": "Are you sure you want to update the secret key?",
"minimizeAppOnCopy": "Minimize app on copy",
"editCodeAuthMessage": "Authenticate to edit code",
"deleteCodeAuthMessage": "Authenticate to delete code",
"showQRAuthMessage": "Authenticate to show QR code",
"confirmAccountDeleteTitle": "Confirm account deletion",
"confirmAccountDeleteMessage": "This account is linked to other ente apps, if you use any.\n\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.",
"androidBiometricHint": "Verify identity",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
},
"androidBiometricNotRecognized": "Not recognized. Try again.",
"@androidBiometricNotRecognized": {
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
},
"androidBiometricSuccess": "Success",
"@androidBiometricSuccess": {
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
},
"androidCancelButton": "Cancel",
"@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": "Authentication required",
"@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": "Biometric required",
"@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": "Device credentials required",
"@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": "Device credentials required",
"@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": "Go to settings",
"@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": "Biometric authentication is not set up on your device. Go to 'Settings > Security' to add biometric authentication.",
"@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": "Biometric authentication is disabled. Please lock and unlock your screen to enable it.",
"@iOSLockOut": {
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
},
"iOSGoToSettingsDescription": "Biometric authentication is not set up on your device. Please either enable Touch ID or Face ID on your phone.",
"@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": "No internet connection",
"pleaseCheckYourInternetConnectionAndTryAgain": "Please check your internet connection and try again.",
"signOutFromOtherDevices": "Sign out from other devices",
"signOutOtherBody": "If you think someone might know your password, you can force all other devices using your account to sign out.",
"signOutOtherDevices": "Sign out other devices",
"doNotSignOut": "Do not sign out",
"hearUsWhereTitle": "How did you hear about Ente? (optional)",
"hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!"
}

View File

@@ -9,8 +9,13 @@
"onBoardingGetStarted": "Primeros pasos",
"setupFirstAccount": "Configura tu primera cuenta",
"importScanQrCode": "Escanear un código QR",
"qrCode": "Código QR",
"importEnterSetupKey": "Ingrese una llave de configuración",
"importAccountPageTitle": "Ingrese los detalles de la cuenta",
"secretCanNotBeEmpty": "El secreto no puede estar vacío",
"bothIssuerAndAccountCanNotBeEmpty": "El emisor y la cuenta no pueden estar vacíos",
"incorrectDetails": "Detalles incorrectos",
"pleaseVerifyDetails": "Por favor, confirma los detalles e intentar otra vez",
"codeIssuerHint": "Emisor",
"codeSecretKeyHint": "Llave Secreta",
"codeAccountHint": "Cuenta (tu@dominio.com)",
@@ -53,6 +58,9 @@
}
},
"contactSupport": "Ponerse en contacto con el equipo de soporte",
"rateUsOnStore": "Califícanos en {storeName}",
"blog": "Blog",
"merchandise": "Mercancías",
"verifyPassword": "Verificar contraseña",
"pleaseWait": "Por favor, espere...",
"generatingEncryptionKeysTitle": "Generando claves de encriptación...",
@@ -68,10 +76,24 @@
"changePassword": "Cambiar contraseña",
"data": "Datos",
"importCodes": "Importar códigos",
"importTypePlainText": "Texto sin formato",
"importTypeEnteEncrypted": "Exportación cifrada ente",
"passwordForDecryptingExport": "Contraseña para descifrar exportación",
"passwordEmptyError": "La contraseña no puede estar vacía",
"importFromApp": "Importar códigos de {appName}",
"importGoogleAuthGuide": "Exportar tus cuentas desde Google Authenticator a un código QR usando la opción \"Transferir Cuentas\". A continuación, usando otro dispositivo, escanee el código QR.\n\nConsejo: Puede usar la webcam de su portátil para tomar una foto del código QR.",
"importSelectJsonFile": "Seleccione el archivo JSON",
"importEnteEncGuide": "Seleccione el archivo JSON cifrado exportado desde ente",
"importRaivoGuide": "Utilice la opción \"Exportar códigos a un archivo de Zip\" en la configuración de Raivo.\n\nExtraiga el archivo zip e importe el archivo JSON.",
"importAegisGuide": "Utilice la opción \"Exportar la bóveda\" en ajustes de Aegis.\n\nSi tu bóveda es cifrada, necesitara entrar contraseña de bóveda para descifrar la bóveda.",
"exportCodes": "Exportar códigos",
"importLabel": "Importar",
"importInstruction": "Por favor, seleccione un archivo que contenga una lista de sus códigos en el siguiente formato",
"importCodeDelimiterInfo": "Los códigos pueden separarse por una coma o una nueva línea",
"selectFile": "Seleccionar archivo",
"emailVerificationToggle": "Verificación de correo electrónico",
"emailVerificationEnableWarning": "Si estás guardando la autenticación de dos factores en tu correo electrónico con nosotros, activar la verificación de correo electrónico podría resultar en un punto muerto. Si está bloqueado fuera de un servicio, puede que no pueda iniciar sesión en el otro.",
"authToChangeEmailVerificationSetting": "Por favor, autentifíquese para cambiar su correo electrónico",
"authToViewYourRecoveryKey": "Por favor, autentifíquese para ver su clave de recuperación",
"authToChangeYourEmail": "Por favor, autentifíquese para cambiar su correo electrónico",
"authToChangeYourPassword": "Por favor, autentifíquese para cambiar su contraseña",
@@ -81,6 +103,7 @@
"no": "No",
"email": "Correo electrónico",
"support": "Soporte",
"general": "General",
"settings": "Configuración",
"copied": "Copiado",
"pleaseTryAgain": "Por favor, inténtalo nuevamente",
@@ -90,6 +113,18 @@
"enterYourPasswordHint": "Ingrese su contraseña",
"forgotPassword": "Olvidé mi contraseña",
"oops": "Ups",
"suggestFeatures": "Sugerir funcionalidades",
"faq": "Preguntas Frecuentes",
"faq_q_1": "¿Cuán seguro es ente Auth?",
"faq_a_1": "Todos los códigos que copia de seguridad vía ente se almacenan cifrados de extremo a extremo. Esto significa que solo usted puede acceder a sus códigos. Nuestras aplicaciones son de código abierto y nuestra criptografía ha sido auditada externamente.",
"faq_q_2": "¿Puedo acceder a mis códigos en el escritorio?",
"faq_a_2": "Puede acceder a tus códigos en la web en auth.ente.io.",
"faq_q_3": "¿Cómo puedo borrar códigos?",
"faq_a_3": "Puede eliminar un código deslizando a la izquierda en ese elemento.",
"faq_q_4": "¿Cómo puedo apoyar este proyecto?",
"faq_a_4": "Puedes apoyar el desarrollo de este proyecto suscribiéndote a nuestra app de Fotos en ente.io.",
"faq_q_5": "¿Cómo puedo habilitar bloqueo FaceID en ente Auth",
"faq_a_5": "Puede activar el bloqueo FaceID en Ajustes → Seguridad → Pantalla de bloqueo.",
"somethingWentWrongMessage": "Algo ha ido mal, por favor, prueba otra vez",
"leaveFamily": "Dejar plan familiar",
"leaveFamilyMessage": "¿Está seguro de que desea abandonar el plan familiar?",
@@ -122,8 +157,6 @@
"yesSendFeedbackAction": "Sí, enviar comentarios",
"noDeleteAccountAction": "No, eliminar cuenta",
"initiateAccountDeleteTitle": "Por favor, autentifíquese para iniciar la eliminación de la cuenta",
"confirmAccountDeleteTitle": "¿Estás seguro de que quieres eliminar tu cuenta de ente?",
"confirmAccountDeleteMessage": "Sus datos subidos a través de todas las aplicaciones (fotos y autenticador), se programarán para su eliminación y su cuenta se eliminará permanentemente.",
"sendEmail": "Enviar correo electrónico",
"createNewAccount": "Crear nueva cuenta",
"weakStrength": "Poco segura",
@@ -140,6 +173,7 @@
"authToChangeLockscreenSetting": "Por favor autentifíquese para cambiar la configuración de bloqueo de pantalla",
"lockScreenEnablePreSteps": "Para activar la pantalla de bloqueo, por favor configure la contraseña del dispositivo o el bloqueo de pantalla en los ajustes de sistema.",
"viewActiveSessions": "Ver sesiones activas",
"authToViewYourActiveSessions": "Por favor, autentifíquese para ver sus sesiones activas",
"searchHint": "Buscar...",
"search": "Buscar",
"sorryUnableToGenCode": "Lo sentimos, no se puede generar un código para {issuerName}",
@@ -149,12 +183,14 @@
"enterDetailsManually": "Ingrese los detalles manualmente",
"edit": "Editar",
"copiedToClipboard": "Copiado al portapapeles",
"copiedNextToClipboard": "Copiado el siguiente código al portapapeles",
"error": "Error",
"recoveryKeyCopiedToClipboard": "Llave de recuperación copiada al portapapeles",
"recoveryKeyOnForgotPassword": "Si olvida su contraseña, la única forma de recuperar sus datos es con esta clave.",
"recoveryKeySaveDescription": "Nosotros no almacenamos esta clave, por favor guarde dicha clave de 24 palabras en un lugar seguro.",
"doThisLater": "Hacer esto más tarde",
"saveKey": "Guardar Clave",
"back": "Atrás",
"createAccount": "Crear cuenta",
"passwordStrength": "Fortaleza de la contraseña: {passwordStrengthValue}",
"@passwordStrength": {
@@ -177,6 +213,9 @@
"changePasswordTitle": "Cambiar contraseña",
"resetPasswordTitle": "Restablecer contraseña",
"encryptionKeys": "Claves de cifrado",
"passwordWarning": "No almacenamos esta contraseña, así que si la olvidas, <underline>no podemos descifrar tus datos</underline>",
"enterPasswordToEncrypt": "Introduzca una contraseña que podamos usar para cifrar sus datos",
"enterNewPasswordToEncrypt": "Introduzca una nueva contraseña que podamos usar para cifrar sus datos",
"passwordChangedSuccessfully": "Contraseña cambiada correctamente",
"generatingEncryptionKeys": "Generando claves de encriptación...",
"continueLabel": "Continuar",
@@ -215,6 +254,10 @@
"privacy": "Privacidad",
"terms": "Términos",
"checkForUpdates": "Comprobar actualizaciones",
"downloadUpdate": "Descargar",
"criticalUpdateAvailable": "Actualización crítica disponible",
"updateAvailable": "Actualizacion disponible",
"update": "Actualizar",
"checking": "Comprobando...",
"youAreOnTheLatestVersion": "Está usando la versión más reciente",
"warning": "Atención",
@@ -224,7 +267,74 @@
"description": "Text for the button to confirm the user understands the warning"
},
"authToExportCodes": "Por favor, autentifíquese para exportar sus códigos",
"importSuccessTitle": "¡Hurra!",
"importSuccessDesc": "¡Has importado {count} códigos!",
"@importSuccessDesc": {
"placeholders": {
"count": {
"description": "The number of codes imported",
"type": "int",
"example": "1"
}
}
},
"sorry": "Lo sentimos",
"importFailureDesc": "No se pudo analizar el archivo seleccionado.\n¡Por favor escriba a support@ente.io si necesita ayuda!",
"pendingSyncs": "Atención"
"pendingSyncs": "Atención",
"pendingSyncsWarningBody": "Algunos de sus códigos no han sido respaldados.\n\nPor favor, asegúrese de tener una copia de seguridad de estos códigos antes de cerrar la sesión.",
"checkInboxAndSpamFolder": "Por favor revisa tu bandeja de entrada (y spam) para completar la verificación",
"tapToEnterCode": "Toca para introducir el código",
"resendEmail": "Reenviar correo electrónico",
"weHaveSendEmailTo": "Hemos enviado un correo a <green>{email}</green>",
"@weHaveSendEmailTo": {
"description": "Text to indicate that we have sent a mail to the user",
"placeholders": {
"email": {
"description": "The email address of the user",
"type": "String",
"example": "example@ente.io"
}
}
},
"activeSessions": "Sesiones activas",
"somethingWentWrongPleaseTryAgain": "Algo ha ido mal, por favor, prueba otra vez",
"thisWillLogYouOutOfThisDevice": "¡Esto cerrará la sesión de este dispositivo!",
"thisWillLogYouOutOfTheFollowingDevice": "Esto cerrará la sesión del siguiente dispositivo:",
"terminateSession": "¿Terminar sesión?",
"terminate": "Terminar",
"thisDevice": "Este dispositivo",
"toResetVerifyEmail": "Para restablecer su contraseña, por favor verifique su correo electrónico primero.",
"thisEmailIsAlreadyInUse": "Este correo electrónico ya está en uso",
"verificationFailedPleaseTryAgain": "Verificación fallida, por favor inténtalo de nuevo",
"yourVerificationCodeHasExpired": "Tu código de verificación ha expirado",
"incorrectCode": "Código incorrecto",
"sorryTheCodeYouveEnteredIsIncorrect": "Lo sentimos, el código que ha introducido es incorrecto",
"emailChangedTo": "Correo electrónico cambiado a {newEmail}",
"authenticationFailedPleaseTryAgain": "Error de autenticación, por favor inténtalo de nuevo",
"authenticationSuccessful": "¡Autenticación exitosa!",
"twofactorAuthenticationSuccessfullyReset": "Autenticación de doble factor restablecida con éxito",
"incorrectRecoveryKey": "Clave de recuperación incorrecta",
"theRecoveryKeyYouEnteredIsIncorrect": "La clave de recuperación introducida es incorrecta",
"enterPassword": "Introduzca la contraseña",
"selectExportFormat": "Seleccionar formato para exportar",
"exportDialogDesc": "Las exportaciones cifradas estarán protegidas por una contraseña de su elección.",
"encrypted": "Cifrado",
"plainText": "Texto sin formato",
"passwordToEncryptExport": "Contraseña para cifrar la exportación",
"export": "Exportar",
"useOffline": "Usar sin copias de seguridad",
"signInToBackup": "Inicia sesión para hacer copia de tus códigos",
"singIn": "Iniciar sesión",
"sigInBackupReminder": "Por favor, exporte sus códigos para asegurarse de que tiene una copia de seguridad de la que puede restaurar.",
"offlineModeWarning": "Ha elegido proceder sin copia de seguridad. Por favor, tome copias de seguridad manuales para asegurarse de que sus códigos están seguros.",
"showLargeIcons": "Mostrar iconos grandes",
"shouldHideCode": "Ocultar códigos",
"focusOnSearchBar": "Enfocar búsqueda al iniciar la aplicación",
"confirmUpdatingkey": "¿Estás seguro de que deseas actualizar la clave secreto?",
"minimizeAppOnCopy": "Minimizar aplicación al copiar",
"editCodeAuthMessage": "Autenticar para editar código",
"deleteCodeAuthMessage": "Autenticar para borrar código",
"showQRAuthMessage": "Autenticar para mostrar código QR",
"confirmAccountDeleteTitle": "Confirmar eliminación de la cuenta",
"confirmAccountDeleteMessage": "Esta cuenta está vinculada a otras aplicaciones de ente, si utiliza alguna.\n\nSe programará la eliminación de los datos que cargue en todas las aplicaciones de ente y su cuenta se eliminará permanentemente."
}

View File

@@ -121,8 +121,6 @@
"yesSendFeedbackAction": "بله، ارسال بازخورد",
"noDeleteAccountAction": "خیر، حساب کاربری را حذف کن",
"initiateAccountDeleteTitle": "لطفا جهت شروع فرآیند حذف حساب کاربری، اعتبارسنجی کنید",
"confirmAccountDeleteTitle": "آیا از حذف حساب کاربری خود اطمینان دارید؟",
"confirmAccountDeleteMessage": "داده‌های آپلود شده شما، در همه برنامه‌ها(هر دو برنامه عکس‌ها و احراز هویت)، طبق زمانبندی و حساب کاربری شما برای همیشه حذف خواهد شد.",
"sendEmail": "ارسال ایمیل",
"createNewAccount": "ایجاد حساب کاربری جدید",
"weakStrength": "ضعیف",
@@ -231,5 +229,8 @@
"importFailureDesc": "نتوانستیم فایل انتخابی را تجزیه و تحلیل کنیم.\nاگر به کمک نیاز دارید، لطفا به support@ente.io ایمیل بزنید!",
"pendingSyncs": "اخطار",
"pendingSyncsWarningBody": "برخی از کدهای شما پشتیبان گیری نشده اند.\n\nلطفا قبل از خروج، مطمئن شوید که یک نسخه پشتیبان برای این کدها دارید.",
"thisDevice": "این دستگاه"
"thisDevice": "این دستگاه",
"editCodeAuthMessage": "احراز هویت برای ویرایش کد",
"deleteCodeAuthMessage": "احراز هویت برای حذف کد",
"showQRAuthMessage": "احراز هویت برای نمایش کد QR"
}

View File

@@ -110,8 +110,6 @@
"yesSendFeedbackAction": "Kyllä, lähetä palautetta",
"noDeleteAccountAction": "En, poista tili",
"initiateAccountDeleteTitle": "Ole hyvä ja tee todennus käynnistääksesi tilisi poistoprosessin",
"confirmAccountDeleteTitle": "Haluatko varmasti poistaa Ente-tilisi?",
"confirmAccountDeleteMessage": "Lataamasi tiedot kaikkien sovellusten kesken (molemmat, sekä kuvat ja todenteet) ajastetaan poistettavaksi ja tilisi poistetaan pysyvästi.",
"sendEmail": "Lähetä sähköpostia",
"createNewAccount": "Luo uusi tili",
"weakStrength": "Heikko salasana",
@@ -119,5 +117,8 @@
"moderateStrength": "Kohtalainen salasana",
"confirmPassword": "Vahvista salasana",
"close": "Sulje",
"oopsSomethingWentWrong": "Hupsista! Jotakin meni nyt pieleen."
"oopsSomethingWentWrong": "Hupsista! Jotakin meni nyt pieleen.",
"editCodeAuthMessage": "Autentikoidu muokataksesi koodia",
"deleteCodeAuthMessage": "Autentikoidu poistaaksesi koodin",
"showQRAuthMessage": "Autentikoidu näyttääksesi QR-koodin"
}

View File

@@ -5,15 +5,20 @@
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "Sécurisez vos codes 2FA",
"onBoardingBody": "Sécurisez vos codes A2F",
"onBoardingGetStarted": "Premiers pas",
"setupFirstAccount": "Configurez votre premier compte",
"importScanQrCode": "Scannez un QR Code",
"qrCode": "Code QR",
"importEnterSetupKey": "Saisir une clé de configuration",
"importAccountPageTitle": "Saisir les détails du compte",
"secretCanNotBeEmpty": "La clé secrète ne peut pas être vide",
"bothIssuerAndAccountCanNotBeEmpty": "L'émetteur et le compte ne peuvent pas être vides",
"incorrectDetails": "Détails incorrects",
"pleaseVerifyDetails": "Veuillez vérifier vos informations et réessayez",
"codeIssuerHint": "Émetteur",
"codeSecretKeyHint": "Clé secrète",
"codeAccountHint": "Compte (vous@domaine.fr)",
"codeAccountHint": "Compte (vous@exemple.com)",
"accountKeyType": "Type de clé",
"sessionExpired": "Session expirée",
"@sessionExpired": {
@@ -53,28 +58,41 @@
}
},
"contactSupport": "Contacter le support",
"rateUsOnStore": "Notez-nous sur {storeName}",
"blog": "Blog",
"merchandise": "Marchandise",
"verifyPassword": "Vérifier le mot de passe",
"pleaseWait": "Veuillez patienter...",
"generatingEncryptionKeysTitle": "Génération des clés de chiffrement...",
"recreatePassword": "Recréer le mot de passe",
"recreatePasswordMessage": "L'appareil actuel n'est pas assez puissant pour vérifier votre mot de passe, donc nous avons besoin de le générer une fois d'une manière qu'il fonctionne avec tous les périphériques.\n\nVeuillez vous connecter en utilisant votre clé de récupération et générer votre mot de passe (vous pouvez utiliser le même si vous le souhaitez).",
"recreatePasswordMessage": "L'appareil utilisé n'est pas assez performant pour vérifier votre mot de passe, nous avons donc besoin de le générer à nouveau d'une manière fonctionnant avec tous les périphériques.\n\nVeuillez vous connecter en utilisant votre clé de récupération et générer à nouveau votre mot de passe (vous pouvez utiliser le même si vous le souhaitez).",
"useRecoveryKey": "Utiliser la clé de récupération",
"incorrectPasswordTitle": "Mot de passe incorrect",
"welcomeBack": "Bon retour parmi nous !",
"madeWithLoveAtPrefix": "fait avec ❤️ à ",
"supportDevs": "Abonnez-vous à <bold-green>ente</bold-green> pour soutenir ce projet.",
"supportDevs": "Abonnez-vous à <bold-green>ente</bold-green> pour nous soutenir",
"supportDiscount": "Utilisez le code coupon \"AUTH\" pour obtenir 10% de réduction sur la première année",
"changeEmail": "Modifier l'e-mail",
"changePassword": "Modifier le mot de passe",
"data": "Données",
"importCodes": "Importer les codes",
"importTypePlainText": "Texte brut",
"importTypeEnteEncrypted": "ente Exportation chiffrée",
"passwordForDecryptingExport": "Mot de passe pour déchiffrer l'exportation",
"passwordEmptyError": "Le mot de passe ne peut pas être vide",
"importFromApp": "Importer des codes depuis {appName}",
"importGoogleAuthGuide": "Exportez vos comptes depuis Google Authenticator vers un code QR en utilisant l'option \"Transférer des comptes\". Ensuite, en utilisant un autre appareil, scannez le code QR.\n\nAstuce : Vous pouvez utiliser la webcam de votre ordinateur portable pour prendre une photo du code QR.",
"importSelectJsonFile": "Sélectionnez un fichier JSON",
"importEnteEncGuide": "Sélectionnez le fichier JSON chiffré exporté à partir de ente",
"importRaivoGuide": "Utilisez l'option \"Exporter les OTPs vers l'archive Zip\" dans les paramètres de Raivo.\n\nExtrayez le fichier zip et importez le fichier JSON.",
"importAegisGuide": "Utilisez l'option \"Exporter le coffre-fort\" dans les paramètres d'Aegis.\n\nSi votre coffre-fort est crypté, vous devrez saisir le mot de passe du coffre-fort pour déchiffrer le coffre-fort.",
"exportCodes": "Exporter les codes",
"importLabel": "Importer",
"importInstruction": "Veuillez sélectionner un fichier qui contient une liste de vos codes dans le format suivant",
"importCodeDelimiterInfo": "Les codes peuvent être séparés par une virgule ou un retour à la ligne",
"selectFile": "Sélectionner le fichier",
"emailVerificationToggle": "Vérification de l'adresse e-mail",
"emailVerificationEnableWarning": "Si vous stockez le 2FA dans votre e-mail avec nous, l'activation de la vérification d'e-mail pourrait entraîner un blocage. Si vous êtes exclu d'un service, il se peut que vous ne puissiez pas vous connecter à l'autre.",
"authToChangeEmailVerificationSetting": "Veuillez vous authentifier pour modifier votre adresse e-mail",
"authToViewYourRecoveryKey": "Veuillez vous authentifier pour afficher votre clé de récupération",
"authToChangeYourEmail": "Veuillez vous authentifier pour modifier votre adresse e-mail",
@@ -85,6 +103,7 @@
"no": "Non",
"email": "E-mail",
"support": "Support",
"general": "Général",
"settings": "Paramètres",
"copied": "Copié",
"pleaseTryAgain": "Veuillez réessayer",
@@ -96,12 +115,16 @@
"oops": "Oups",
"suggestFeatures": "Suggérer des fonctionnalités",
"faq": "FAQ",
"faq_q_1": "À quel point ente Auth est-il sécurisé ?",
"faq_a_1": "Tous les codes que vous sauvegardez via ente sont chiffrés de bout en bout. Cela signifie que vous seul pouvez accéder à vos codes. Nos applications sont open source et notre cryptographie a fait l'objet d'un audit externe.",
"faq_q_2": "Puis-je accéder à mes codes sur mon ordinateur ?",
"faq_a_2": "Vous pouvez accéder à vos codes sur le web via auth.ente.io.",
"faq_q_3": "Comment puis-je supprimer des codes ?",
"faq_a_3": "Vous pouvez supprimer un code en glissant vers la gauche.",
"faq_q_4": "Comment puis-je soutenir le projet?",
"faq_q_4": "Comment puis-je soutenir le projet ?",
"faq_a_4": "Vous pouvez soutenir le développement de ce projet en vous abonnant à notre application Photos, ente.io.",
"faq_q_5": "Comment puis-je activer le verrouillage FaceID sur ente Auth",
"faq_a_5": "Vous pouvez activer le verrouillage FaceID dans Paramètres → Sécurité → Écran de verrouillage.",
"somethingWentWrongMessage": "Quelque chose s'est mal passé, veuillez recommencer",
"leaveFamily": "Quitter le plan familial",
"leaveFamilyMessage": "Êtes-vous certains de vouloir quitter le plan familial?",
@@ -110,7 +133,7 @@
"scan": "Analyser",
"scanACode": "Scanner un code",
"verify": "Vérifier",
"verifyEmail": "Vérifier l'email",
"verifyEmail": "Vérifier l'e-mail",
"enterCodeHint": "Saisir le code à 6 caractères de votre appli d'authentification",
"lostDeviceTitle": "Appareil perdu ?",
"twoFactorAuthTitle": "Authentification à deux facteurs",
@@ -127,15 +150,13 @@
},
"noRecoveryKeyTitle": "Pas de clé de récupération ?",
"enterEmailHint": "Entrez votre adresse e-mail",
"invalidEmailTitle": "Adresse e-mail non valide",
"invalidEmailTitle": "Adresse e-mail invalide",
"invalidEmailMessage": "Veuillez saisir une adresse e-mail valide.",
"deleteAccount": "Supprimer le compte",
"deleteAccountQuery": "Nous sommes désolés de vous voir partir. Êtes-vous confronté à un problème?",
"deleteAccountQuery": "Nous sommes désolés de vous voir partir. Rencontrez-vous un problème ?",
"yesSendFeedbackAction": "Oui, envoyer un commentaire",
"noDeleteAccountAction": "Non, supprimer le compte",
"initiateAccountDeleteTitle": "Veuillez vous authentifier pour débuter la suppression du compte",
"confirmAccountDeleteTitle": "Êtes-vous sûr de vouloir supprimer votre compte ente ?",
"confirmAccountDeleteMessage": "Vos données téléchargées, à travers toutes les applications (Photos et Authenticator), seront planifiées pour la suppression, et votre compte sera définitivement supprimé.",
"sendEmail": "Envoyer un e-mail",
"createNewAccount": "Créer un nouveau compte",
"weakStrength": "Faible",
@@ -143,7 +164,7 @@
"moderateStrength": "Modéré",
"confirmPassword": "Confirmer le mot de passe",
"close": "Fermer",
"oopsSomethingWentWrong": "Oops ! Une erreur s'est produite.",
"oopsSomethingWentWrong": "Oups, une erreur s'est produite.",
"selectLanguage": "Sélectionnez la langue",
"language": "Langue",
"social": "Réseaux Sociaux",
@@ -152,7 +173,7 @@
"authToChangeLockscreenSetting": "Veuillez vous authentifier pour modifier les paramètres de l'écran de verrouillage",
"lockScreenEnablePreSteps": "Pour activer l'écran de verrouillage, veuillez configurer le code d'accès de l'appareil ou le verrouillage de l'écran dans les paramètres de votre système.",
"viewActiveSessions": "Afficher les sessions actives",
"authToViewYourActiveSessions": "Veuillez vous authentifier pour voir vos sessions actives",
"authToViewYourActiveSessions": "Veuillez vous authentifier pour afficher vos sessions actives",
"searchHint": "Rechercher...",
"search": "Rechercher",
"sorryUnableToGenCode": "Désolé, impossible de générer un code pour {issuerName}",
@@ -162,6 +183,7 @@
"enterDetailsManually": "Saisir les détails manuellement",
"edit": "Éditer",
"copiedToClipboard": "Copié dans le presse-papiers",
"copiedNextToClipboard": "Code suivant copié dans le presse-papiers",
"error": "Erreur",
"recoveryKeyCopiedToClipboard": "Clé de récupération copiée dans le presse-papiers",
"recoveryKeyOnForgotPassword": "Si vous oubliez votre mot de passe, la seule façon de récupérer vos données sera grâce à cette clé.",
@@ -191,7 +213,7 @@
"changePasswordTitle": "Modifier le mot de passe",
"resetPasswordTitle": "Réinitialiser le mot de passe",
"encryptionKeys": "Clés de chiffrement",
"passwordWarning": "Nous ne stockons pas ce mot de passe, donc si vous l'oubliez, <underline>nous ne pouvons pas déchiffrer vos données</underline>",
"passwordWarning": "Nous ne stockons pas ce mot de passe. Si vous l'oubliez, <underline>nous ne pourrons pas déchiffrer vos données</underline>",
"enterPasswordToEncrypt": "Entrez un mot de passe que nous pouvons utiliser pour chiffrer vos données",
"enterNewPasswordToEncrypt": "Entrez un nouveau mot de passe que nous pouvons utiliser pour chiffrer vos données",
"passwordChangedSuccessfully": "Le mot de passe a été modifié avec succès",
@@ -204,7 +226,7 @@
"loginTerms": "En cliquant sur \"Connexion\", j'accepte les <u-terms>conditions d'utilisation</u-terms> et la <u-policy>politique de confidentialité</u-policy>",
"logInLabel": "Connexion",
"logout": "Déconnexion",
"areYouSureYouWantToLogout": "Voulez-vous vraiment vous déconnecter?",
"areYouSureYouWantToLogout": "Êtes-vous sûr de vouloir vous déconnecter ?",
"yesLogout": "Oui, se déconnecter",
"exit": "Quitter",
"verifyingRecoveryKey": "Vérification de la clé de récupération...",
@@ -215,7 +237,7 @@
"recreatePasswordBody": "L'appareil actuel n'est pas assez puissant pour vérifier votre mot de passe, donc nous avons besoin de le régénérer une fois d'une manière qu'il fonctionne avec tous les périphériques.\n\nVeuillez vous connecter en utilisant votre clé de récupération et régénérer votre mot de passe (vous pouvez utiliser le même si vous le souhaitez).",
"invalidKey": "Clé non valide",
"tryAgain": "Réessayer",
"viewRecoveryKey": "Voir la clé de récupération",
"viewRecoveryKey": "Afficher la clé de récupération",
"confirmRecoveryKey": "Confirmer la clé de récupération",
"recoveryKeyVerifyReason": "Votre clé de récupération est la seule façon de récupérer vos photos si vous oubliez votre mot de passe. Vous pouvez trouver votre clé de récupération dans Paramètres > Compte.\n\nVeuillez entrer votre clé de récupération ici pour vous assurer que vous l'avez enregistrée correctement.",
"confirmYourRecoveryKey": "Confirmer la clé de récupération",
@@ -232,6 +254,10 @@
"privacy": "Confidentialité",
"terms": "Conditions",
"checkForUpdates": "Vérifier les mises à jour",
"downloadUpdate": "Télécharger",
"criticalUpdateAvailable": "Mise à jour critique disponible",
"updateAvailable": "Une mise à jour est disponible",
"update": "Mise à jour",
"checking": "Vérification...",
"youAreOnTheLatestVersion": "Vous êtes sur la dernière version",
"warning": "Attention",
@@ -290,5 +316,25 @@
"incorrectRecoveryKey": "Clé de récupération non valide",
"theRecoveryKeyYouEnteredIsIncorrect": "La clé de récupération que vous avez entrée est incorrecte",
"enterPassword": "Saisissez le mot de passe",
"export": "Exporter"
"selectExportFormat": "Choisir le format d'exportation",
"exportDialogDesc": "Les exportations chiffrées seront protégées par un mot de passe de votre choix.",
"encrypted": "Chiffré",
"plainText": "Texte brut",
"passwordToEncryptExport": "Mot de passe pour chiffrer l'export",
"export": "Exporter",
"useOffline": "Utiliser sans sauvegardes",
"signInToBackup": "Connectez-vous pour sauvegarder vos codes",
"singIn": "Se connecter",
"sigInBackupReminder": "Veuillez exporter vos codes pour vous assurer que vous avez une sauvegarde à partir de laquelle vous pouvez restaurer.",
"offlineModeWarning": "Vous avez choisi de procéder sans sauvegarde. Veuillez prendre des sauvegardes manuelles pour vous assurer que vos codes sont sûrs.",
"showLargeIcons": "Afficher les grandes icônes",
"shouldHideCode": "Cacher les codes",
"focusOnSearchBar": "Cibler le champ de recherche au démarrage de l'application",
"confirmUpdatingkey": "Êtes-vous sûr de vouloir mettre à jour la clé secrète ?",
"minimizeAppOnCopy": "Réduire l'application après la copie",
"editCodeAuthMessage": "Authentification requise pour modifier le code",
"deleteCodeAuthMessage": "Authentification requise pour supprimer le code",
"showQRAuthMessage": "Authentification requise pour afficher le code QR",
"confirmAccountDeleteTitle": "Confirmer la suppression du compte",
"confirmAccountDeleteMessage": "Ce compte peut être lié à d'autres applications ente.\n\nVos données seront bientôt effacées de toutes les applications et votre compte sera définitivement supprimé."
}

338
lib/l10n/arb/app_he.arb Normal file
View File

@@ -0,0 +1,338 @@
{
"account": "חשבון",
"recoveryKey": "מפתח שחזור",
"counterAppBarTitle": "מונה",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "גיבוי מאובטח של קודי האימות שלך",
"onBoardingGetStarted": "התחילו",
"setupFirstAccount": "התקנה של החשבון הראשון שלך",
"importScanQrCode": "סרוק קוד QR",
"qrCode": "קוד QR",
"importEnterSetupKey": "הכנס מפתח התקנה",
"importAccountPageTitle": "הכנס פרטי חשבון",
"secretCanNotBeEmpty": "סוד לא יכול להיות ריק",
"bothIssuerAndAccountCanNotBeEmpty": "גם המנפיק והחשבון לא יכולים להיות ריקים",
"incorrectDetails": "פרטים לא נכונים",
"pleaseVerifyDetails": "אנא אמתו את הפרטים ונסו שוב",
"codeIssuerHint": "מנפיק",
"codeSecretKeyHint": "מפתח סודי",
"codeAccountHint": "חשבון(you@domain.com)",
"accountKeyType": "סוג מפתח",
"sessionExpired": "זמן החיבור הסתיים",
"@sessionExpired": {
"description": "Title of the dialog when the users current session is invalid/expired"
},
"pleaseLoginAgain": "אנא התחבר שוב",
"loggingOut": "מתנתק...",
"timeBasedKeyType": "מבוסס זמן(TOTP)",
"counterBasedKeyType": "מבוסס מונה(HOTP)",
"saveAction": "שמור",
"nextTotpTitle": "הבא",
"deleteCodeTitle": "מחק קוד?",
"deleteCodeMessage": "האם אתה בטוח שברצונך למחוק את הקוד הזה? פעולה זו היא בלתי הפיכה.",
"viewLogsAction": "צפייה ביומן",
"sendLogsDescription": "זה ישלח לוגים לנו כדי לעזור לנו לדבג את הבעיה שלך. אנחנו לוקחים אמצעי זהירות כדי לוודא שמידע רגיש לא יהיה בלוגים, אנו מעודדים אותך לעבור על הלוגים האלו לפני שאתה משתף אותם.",
"preparingLogsTitle": "מכין לוגים...",
"emailLogsTitle": "לשלוח לוגים באימייל",
"emailLogsMessage": "אנא שלחו את הלוגים האלו ל-{email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "העתק אימייל",
"exportLogsAction": "ייצוא לוגים",
"reportABug": "דווח על באג",
"crashAndErrorReporting": "דיווח על שגיאות וקריסות",
"reportBug": "דווח על באג",
"emailUsMessage": "אנא שלחו לנו אימייל ב-{email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "צור קשר עם התמיכה",
"rateUsOnStore": "דרג אותנו ב-{storeName}",
"blog": "בלוג",
"merchandise": "סחורה",
"verifyPassword": "אמת סיסמא",
"pleaseWait": "אנא המתן...",
"generatingEncryptionKeysTitle": "יוצר מפתחות הצפנה...",
"recreatePassword": "צור סיסמא מחדש",
"recreatePasswordMessage": "המכשיר הנוכחי אינו חזק מספיק כדי לאמת את הסיסמא שלך, אז אנחנו צריכים ליצור אותו מחדש בצורה שתעבוד עם כל המכשירים.\n\nאנא התחבר בעזרת המפתח שחזור שלך וצור מחדש את הסיסמא שלך (אתה יכול להשתמש באותה אחת אם אתה רוצה).",
"useRecoveryKey": "השתמש במפתח שחזור",
"incorrectPasswordTitle": "סיסמא לא נכונה",
"welcomeBack": "ברוך שובך!",
"madeWithLoveAtPrefix": "נעשה עם ❤️ ב- ",
"supportDevs": "הירשם ל-<bold-green>ente</bold-green> כדי לתמוך בנו",
"supportDiscount": "השתמש בקוד קופון \"AUTH\" כדי לקבל 10% הנחה לשנה הראשונה",
"changeEmail": "שנה דוא\"ל",
"changePassword": "שנה סיסמה",
"data": "נתונים",
"importCodes": "ייבא קוד",
"importTypePlainText": "טקסט רגיל",
"importTypeEnteEncrypted": "ייצוא ente מוצפן",
"passwordForDecryptingExport": "סיסמא כדי לפענח יצוא",
"passwordEmptyError": "הסיסמה אינה יכולה להיות ריקה",
"importFromApp": "יבא קודים מ-{appName}",
"importGoogleAuthGuide": "יצא את החשבונות שלך מ-Google Authenticator לקוד QR תוך שימוש באפשרות \"Transfer Accounts\". אז, תוך שימוש במכשיר אחר, סרוק את הקוד QR.",
"importSelectJsonFile": "בחר קובץ JSON",
"importEnteEncGuide": "בחר את קובץ ה-JSON המוצפן שייוצא מ-ente",
"importRaivoGuide": "השתמש באפוציה של \"Export OTPs to Zip archive\" בהגדרות של Raivo.",
"importAegisGuide": "אנא השתמש באפשרות של \"ייצוא של הכספת\" בתוך ההגדרות של Aegis.",
"exportCodes": "ייצא קודים",
"importLabel": "יבוא",
"importInstruction": "אנא בחר קובץ שמכיל רשימה של הקודים שלך לפי הפורמט הבא",
"importCodeDelimiterInfo": "הקודים יכולים להיות מופרדים על-ידי פסיק או שורה חדשה",
"selectFile": "בחר קובץ",
"emailVerificationToggle": "אימות אימייל",
"emailVerificationEnableWarning": "אם אתם מאחסנים את האימות הדו שלבי לאיימיל שלך איתנו, הדלקה של אימות אימייל יכול להגיע לנעילה. אם אתם ננעלים מחוץ לאחד השירותים, אתם אולי לא תצליחו להתחבר לאחר.",
"authToChangeEmailVerificationSetting": "אנא התאמת על מנת לשנות את אימות הדוא\"ל",
"authToViewYourRecoveryKey": "אנא אמת על מנת לראות את מפתח השחזור שלך",
"authToChangeYourEmail": "אנא אמת על מנת לשנות את הסיסמא שלך",
"authToChangeYourPassword": "אנא אמת על מנת לשנות את הסיסמא שלך",
"ok": "אוקיי",
"cancel": "בטל",
"yes": "כן",
"no": "לא",
"email": "דוא\"ל",
"support": "תמיכה",
"general": "כללי",
"settings": "הגדרות",
"copied": "הועתק",
"pleaseTryAgain": "אנא נסה שנית",
"existingUser": "משתמש קיים",
"newUser": "חדש בente",
"delete": "למחוק",
"enterYourPasswordHint": "הכנס סיסמא",
"forgotPassword": "שכחתי סיסמה",
"oops": "אופס",
"suggestFeatures": "הציעו מאפיינים",
"faq": "שאלות נפוצות",
"faq_q_1": "כמה מאובטח ente Auth?",
"faq_a_1": "כל הקודים שאתה מגבה דרך ente מאוחסנים מקצה לקצה בהצפנה. הכוונה שרק אתה יכול לגשת לקודים שלך. האפליקציות שלנו הם מפותחות דרך קוד פתוח והקריפטוגרפיה שלנו מבוקרת חיצונית.",
"faq_q_2": "האם ישנה אפשרות להשתמש בקודים שלי במחשב?",
"faq_a_2": "אתה יכול לגשת לקודים שלך ברשת ב- auth.ente.io.",
"faq_q_3": "איך אפשר למחוק קודים?",
"faq_a_3": "אתה יכול למחוק את הקוד על-ידי החלקה שמאלה על הפריט הזה.",
"faq_q_4": "איך אפשר לתמוך בפרויקט זה?",
"faq_a_4": "אתה יכול לתמוך בפיתוח של הפרויקט הזה על ידי שתירשם לאפליקצית תמונות שלנו ב-ente.io.",
"faq_q_5": "איך אני יכול להפעיל מנעול FaceID ב-ente Auth",
"faq_a_5": "אתה יכול להפעיל מנעול FaceID תחת הגדרות -> אבטחה -> מסך נעילה.",
"somethingWentWrongMessage": "משהו השתבש, אנא נסה שנית",
"leaveFamily": "עזוב משפחה",
"leaveFamilyMessage": "האם אתה בטוח שאתה רוצה לעזוב את התוכנית המשפחתית?",
"inFamilyPlanMessage": "אתה על תוכנית משפחתית!",
"swipeHint": "החלק שמאלה כדי לערוך או להסיר קודים",
"scan": "סרוק",
"scanACode": "סרוק קוד",
"verify": "אמת",
"verifyEmail": "אימות דוא\"ל",
"enterCodeHint": "הכנס את הקוד בעל 6 ספרות מתוך\nאפליקציית האימות שלך",
"lostDeviceTitle": "איבדת את המכשיר?",
"twoFactorAuthTitle": "אימות דו-שלבי",
"recoverAccount": "שחזר חשבון",
"enterRecoveryKeyHint": "הזן את מפתח השחזור שלך",
"recover": "שחזר",
"contactSupportViaEmailMessage": "אנא תשלח דוא\"ל ל{email} מהכתובת דוא\"ל שנרשמת איתה",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"noRecoveryKeyTitle": "אין מפתח שחזור?",
"enterEmailHint": "הכנס את כתובת הדוא״ל שלך",
"invalidEmailTitle": "כתובת דוא״ל לא תקינה",
"invalidEmailMessage": "אנא הכנס כתובת דוא\"ל תקינה.",
"deleteAccount": "מחק חשבון",
"deleteAccountQuery": "אנו מצטערים שאתה עוזב. האם יש בעיות שאתה חווה?",
"yesSendFeedbackAction": "כן, שלח משוב",
"noDeleteAccountAction": "לא, מחק את החשבון",
"initiateAccountDeleteTitle": "אנא אמת על מנת להתחיל את מחיקת החשבון שלך",
"sendEmail": "שלח אימייל",
"createNewAccount": "צור חשבון חדש",
"weakStrength": "חלש",
"strongStrength": "חזק",
"moderateStrength": "מתון",
"confirmPassword": "אמת סיסמא",
"close": "סגור",
"oopsSomethingWentWrong": "אופס, משהו השתבש.",
"selectLanguage": "בחר שפה",
"language": "שפה",
"social": "חברתי",
"security": "אבטחה",
"lockscreen": "מסך נעילה",
"authToChangeLockscreenSetting": "אנא בצע אימות כדי לשנות את הגדרות מסך הנעילה",
"lockScreenEnablePreSteps": "כדי לאפשר את מסך הנעילה, אנא הגדר קוד גישה למכשיר או לנעילת מסך בהגדרות המערכת שלך.",
"viewActiveSessions": "צפה בחיבורים פעילים",
"authToViewYourActiveSessions": "אנא בצע איומת על מנת לראות את החיבורים הפעילים שלך",
"searchHint": "חיפוש...",
"search": "חיפוש",
"sorryUnableToGenCode": "אנו מתנצלים, לא הצלחנו ליצור קוד עבור {issuerName}",
"noResult": "אין תוצאות",
"addCode": "הוסף קוד",
"scanAQrCode": "סרוק קוד QR",
"enterDetailsManually": "הכנס פרטים באופן ידני",
"edit": "עריכה",
"copiedToClipboard": "הועתק ללוח הגזירים",
"copiedNextToClipboard": "הקוד הבא הועתק ללוח הכתיבה",
"error": "שגיאה",
"recoveryKeyCopiedToClipboard": "מפתח השחזור הועתק ללוח",
"recoveryKeyOnForgotPassword": "אם אתה שוכח את הסיסמא שלך, הדרך היחידה שתוכל לשחזר את המידע שלך היא עם המפתח הזה.",
"recoveryKeySaveDescription": "אנחנו לא מאחסנים את המפתח הזה, אנא שמור את המפתח 24 מילים הזה במקום בטוח.",
"doThisLater": "עשה זאת מאוחר יותר",
"saveKey": "שמור מפתח",
"back": "חזרה",
"createAccount": "צור חשבון",
"passwordStrength": "חוזק הסיסמא: {passwordStrengthValue}",
"@passwordStrength": {
"description": "Text to indicate the password strength",
"placeholders": {
"passwordStrengthValue": {
"description": "The strength of the password as a string",
"type": "String",
"example": "Weak or Moderate or Strong"
}
},
"message": "Password Strength: {passwordStrengthText}"
},
"password": "סיסמא",
"signUpTerms": "אני מסכים ל<u-terms>תנאי שירות</u-terms> ול<u-policy>מדיניות הפרטיות</u-policy>",
"privacyPolicyTitle": "מדיניות פרטיות",
"termsOfServicesTitle": "תנאים",
"encryption": "הצפנה",
"setPasswordTitle": "הגדר סיסמא",
"changePasswordTitle": "שנה סיסמה",
"resetPasswordTitle": "איפוס סיסמה",
"encryptionKeys": "מפתחות ההצפנה",
"passwordWarning": "אנחנו לא שומרים את הסיסמא הזו, לכן אם אתה שוכח אותה, <underline>אנחנו לא יכולים לפענח את המידע שלך</underline>",
"enterPasswordToEncrypt": "הזן סיסמא כדי שנוכל להצפין את המידע שלך",
"enterNewPasswordToEncrypt": "הכנס סיסמא חדשה כדי שנוכל להצפין את המידע שלך",
"passwordChangedSuccessfully": "הסיסמה הוחלפה בהצלחה",
"generatingEncryptionKeys": "יוצר מפתחות הצפנה...",
"continueLabel": "המשך",
"insecureDevice": "מכשיר בלתי מאובטח",
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "אנחנו מצטערים, לא הצלחנו ליצור מפתחות מאובטחים על מכשיר זה.\n\nאנא הירשם ממכשיר אחר.",
"howItWorks": "איך זה עובד",
"ackPasswordLostWarning": "אני מבין שאם אאבד את הסיסמא, אני עלול לאבד את המידע שלי מכיוון שהמידע שלי <underline>מוצפן מקצה אל קצה</underline>.",
"loginTerms": "על ידי לחיצה על התחברות, אני מסכים ל<u-terms>תנאי שירות</u-terms> ול<u-policy>מדיניות הפרטיות</u-policy>",
"logInLabel": "התחבר",
"logout": "התנתק/י",
"areYouSureYouWantToLogout": "האם את/ה בטוח/ה שאת/ה רוצה לצאת?",
"yesLogout": "כן, התנתק",
"exit": "יציאה",
"verifyingRecoveryKey": "מוודא את מפתח השחזור...",
"recoveryKeyVerified": "מפתח השחזור אומת",
"recoveryKeySuccessBody": "נהדר! מפתח השחזור תקין. אנחנו מודים לך על האימות.\n\nאנא תזכור לגבות את מפתח השחזור שלך באופן בטוח.",
"invalidRecoveryKey": "מפתח השחזור שהזנת אינו תקין. אנא וודא שהוא מכיל 24 מילים, ותבדוק את האיות של כל אחת.\n\nאם הכנסת קוד שחזור ישן, וודא שהוא בעל 64 אותיות, ותבדוק כל אחת מהן.",
"recreatePasswordTitle": "צור סיסמא מחדש",
"recreatePasswordBody": "המכשיר הנוכחי אינו חזק מספיק כדי לאמת את הסיסמא שלך, אבל אנחנו יכולים ליצור מחדש בצורה שתעבוד עם כל המכשירים.\n\nאנא התחבר בעזרת המפתח שחזור שלך וצור מחדש את הסיסמא שלך (אתה יכול להשתמש באותה אחת אם אתה רוצה).",
"invalidKey": "מפתח לא חוקי",
"tryAgain": "נסה שוב",
"viewRecoveryKey": "צפה במפתח השחזור",
"confirmRecoveryKey": "אמת את מפתח השחזור",
"recoveryKeyVerifyReason": "מפתח השחזור שלך הוא הדרך היחידה לשחזר את התמונות שלך במקרה ותשכח את הסיסמא שלך. אתה יכול למצוא את מפתח השחזור שלך ב-הגדרות > חשבון.\n\nאנא הכנס את מפתח השחזור שלך כאן על מנת לוודא ששמרת אותו כשורה.",
"confirmYourRecoveryKey": "אמת את מפתח השחזור שלך",
"confirm": "אשר",
"emailYourLogs": "שלח באימייל את הלוגים שלך",
"pleaseSendTheLogsTo": "אנא שלחו את הלוגים האלו ל-{toEmail}",
"copyEmailAddress": "העתק כתובת דוא\"ל",
"exportLogs": "ייצוא לוגים",
"enterYourRecoveryKey": "הזן את מפתח השחזור שלך",
"tempErrorContactSupportIfPersists": "נראה שמשהו לא פעל כשורה. אנא נסה שוב אחרי כמה זמן. אם הבעיה ממשיכה, אנא צור קשר עם צוות התמיכה שלנו.",
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "נראה שמשהו לא פעל כשורה. אנא נסה שוב אחרי כמה זמן. אם הבעיה ממשיכה, אנא צור קשר עם צוות התמיכה שלנו.",
"about": "אודות",
"weAreOpenSource": "הקוד שלנו פתוח!",
"privacy": "פרטיות",
"terms": "תנאים",
"checkForUpdates": "בדוק אם קיימים עדכונים",
"downloadUpdate": "הורד",
"criticalUpdateAvailable": "עדכון חשוב זמין",
"updateAvailable": "עדכון זמין",
"update": "עדכן",
"checking": "בודק...",
"youAreOnTheLatestVersion": "אתה על הגרסא הכי עדכנית",
"warning": "אזהרה",
"exportWarningDesc": "הקובץ שייוצא מכיל מידע רגיש. אנא שמור אותו מאובטח.",
"iUnderStand": "אני מבין",
"@iUnderStand": {
"description": "Text for the button to confirm the user understands the warning"
},
"authToExportCodes": "אנא בצע אימות כדי לייצא את הקודים שלך",
"importSuccessTitle": "הידד!",
"importSuccessDesc": "אתה ייבאת {count} קודים!",
"@importSuccessDesc": {
"placeholders": {
"count": {
"description": "The number of codes imported",
"type": "int",
"example": "1"
}
}
},
"sorry": "צר לנו",
"importFailureDesc": "האפליקציה לא הצליחה לקרוא את הקובץ הנבחר.\nאנא כתוב מייל ל-support@ente.io אם אתה צריך עזרה!",
"pendingSyncs": "אזהרה",
"pendingSyncsWarningBody": "חלק מהקודים שלך לא גובו.\n\nאנא ודא שיש לך גיבוי לקודים האלו לפני שאתה מתנתק.",
"checkInboxAndSpamFolder": "אנא בדוק את תיבת הדואר שלך (והספאם) כדי להשלים את האימות",
"tapToEnterCode": "הקש כדי להזין את הקוד",
"resendEmail": "שלח דוא\"ל מחדש",
"weHaveSendEmailTo": "שלחנו דוא\"ל ל<green>{email}</green>",
"@weHaveSendEmailTo": {
"description": "Text to indicate that we have sent a mail to the user",
"placeholders": {
"email": {
"description": "The email address of the user",
"type": "String",
"example": "example@ente.io"
}
}
},
"activeSessions": "חיבורים פעילים",
"somethingWentWrongPleaseTryAgain": "משהו השתבש, אנא נסה שנית",
"thisWillLogYouOutOfThisDevice": "זה ינתק אותך במכשיר זה!",
"thisWillLogYouOutOfTheFollowingDevice": "זה ינתק אותך מהמכשיר הבא:",
"terminateSession": "סיים חיבור?",
"terminate": "סיים",
"thisDevice": "מכשיר זה",
"toResetVerifyEmail": "כדי לאפס את הסיסמא שלך, אנא אמת את האימייל שלך קודם.",
"thisEmailIsAlreadyInUse": "כתובת דואר אלקטרוני זאת כבר נמצאת בשימוש",
"verificationFailedPleaseTryAgain": "אימות נכשל, אנא נסה שנית",
"yourVerificationCodeHasExpired": "קוד האימות שלך פג תוקף",
"incorrectCode": "קוד שגוי",
"sorryTheCodeYouveEnteredIsIncorrect": "אנו מתנצלים, אבל הקוד שהזנת איננו נכון",
"emailChangedTo": "אימייל שונה ל-{newEmail}",
"authenticationFailedPleaseTryAgain": "אימות נכשל, אנא נסה שוב",
"authenticationSuccessful": "אימות הצליח!",
"twofactorAuthenticationSuccessfullyReset": "אימות דו-שלבי אופס בהצלחה",
"incorrectRecoveryKey": "מפתח שחזור שגוי",
"theRecoveryKeyYouEnteredIsIncorrect": "המפתח שחזור שהזנת שגוי",
"enterPassword": "הזן את הסיסמה",
"selectExportFormat": "בחר פורמט ייצוא",
"exportDialogDesc": "יצוא מוצפן יהיה מוגן על ידי סיסמא שאתה תבחר.",
"encrypted": "מוצפן",
"plainText": "טקסט רגיל",
"passwordToEncryptExport": "סיסמא כדי להצפין יצוא",
"export": "יצוא",
"useOffline": "השתמש בלי גיבוי",
"signInToBackup": "אנא התחבר כדי לבצע גיבוי לקודים שלך",
"singIn": "התחברות",
"sigInBackupReminder": "אנא ייצא את הקודים שלך כדי לוודא שיש לך גיבוי שניתן לשחזר ממנו.",
"offlineModeWarning": "בחרת להמשיך ללא גיבויים. אנא בצע גיבויים ידניים כדי לוודא שהקודים שלך בטוחים.",
"showLargeIcons": "הצג סמלים גדולים",
"shouldHideCode": "הסתר קודים",
"focusOnSearchBar": "התמקד בחיפוש בהתחלת האפליקציה",
"confirmUpdatingkey": "האם אתה בטוח שברצונך לעדכן את המפתח הסודי?",
"minimizeAppOnCopy": "מזער אפליקציה בהעתקה",
"editCodeAuthMessage": "אמת כדי לערוך קוד",
"deleteCodeAuthMessage": "אמת כדי למחוק קוד",
"showQRAuthMessage": "אמת כדי להראות קוד QR"
}

View File

@@ -92,6 +92,7 @@
"importCodeDelimiterInfo": "I codici possono essere separati da una virgola o da una nuova riga",
"selectFile": "Seleziona file",
"emailVerificationToggle": "Verifica email",
"emailVerificationEnableWarning": "Se memorizzate il 2FA per accedere alla vostra email con noi, l'attivazione della verifica dell'email potrebbe provocare dei problemi. Se siete rimasti bloccati fuori da un servizio, potreste non essere in grado di accedere anche all'altro.",
"authToChangeEmailVerificationSetting": "Autenticati per cambiare la verifica email",
"authToViewYourRecoveryKey": "Autenticati per visualizzare la tua chiave di recupero",
"authToChangeYourEmail": "Autenticati per cambiare la tua email",
@@ -156,8 +157,6 @@
"yesSendFeedbackAction": "Sì, invia un feedback",
"noDeleteAccountAction": "No, elimina l'account",
"initiateAccountDeleteTitle": "Si prega di autenticarsi per avviare l'eliminazione dell'account",
"confirmAccountDeleteTitle": "Sei sicuro di voler eliminare il tuo account?",
"confirmAccountDeleteMessage": "I tuoi dati caricati, in tutte le app (sia foto che autenticatore), verranno pianificati per la cancellazione, e il tuo account sarà eliminato in modo permanente.",
"sendEmail": "Invia email",
"createNewAccount": "Crea un nuovo account",
"weakStrength": "Debole",
@@ -329,5 +328,13 @@
"sigInBackupReminder": "Si prega di esportare i codici per assicurarsi di avere un backup da cui è possibile ripristinare.",
"offlineModeWarning": "Hai scelto di procedere senza backup. Si prega di eseguire backup manuali per assicurarsi che i codici siano al sicuro.",
"showLargeIcons": "Mostra icone grandi",
"focusOnSearchBar": "Apri ricerca all'avvio dell'app"
"shouldHideCode": "Nascondi i codici",
"focusOnSearchBar": "Apri ricerca all'avvio dell'app",
"confirmUpdatingkey": "Sei sicuro di voler aggiornare la chiave segreta?",
"minimizeAppOnCopy": "Riduci a icona l'app dopo la copia",
"editCodeAuthMessage": "Autenticarsi per modificare il codice",
"deleteCodeAuthMessage": "Autenticarsi per cancellare il codice",
"showQRAuthMessage": "Autenticarsi per mostrare il codice QR",
"confirmAccountDeleteTitle": "Conferma l'eliminazione dell'account",
"confirmAccountDeleteMessage": "Questo account è collegato ad altre app di ente, se ne utilizzi.\n\nI tuoi dati caricati, su tutte le app di ente, saranno pianificati per la cancellazione e il tuo account verrà eliminato definitivamente."
}

View File

@@ -1,32 +1,37 @@
{
"account": "アカウント",
"recoveryKey": "回復キー",
"counterAppBarTitle": "カウンタ",
"counterAppBarTitle": "カウンタ",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "2要素認証コードの保護",
"onBoardingBody": "2要素認証コードを安全にバックアップ",
"onBoardingGetStarted": "さあ、はじめよう",
"setupFirstAccount": "最初のアカウントを設定しましょう",
"importScanQrCode": "QRコードをスキャン",
"importEnterSetupKey": "セットアップキーを入力",
"importScanQrCode": "QR コードを読み取り",
"qrCode": "QR コード",
"importEnterSetupKey": "手動で入力",
"importAccountPageTitle": "アカウントの詳細を入力",
"secretCanNotBeEmpty": "秘密鍵は空欄にできません",
"bothIssuerAndAccountCanNotBeEmpty": "発行者とアカウントの両方を空欄にはできません",
"incorrectDetails": "不正な詳細",
"pleaseVerifyDetails": "詳細を確認し、もう一度お試しください",
"codeIssuerHint": "発行者",
"codeSecretKeyHint": "シークレットキー",
"codeSecretKeyHint": "秘密鍵",
"codeAccountHint": "アカウント (you@domain.com)",
"accountKeyType": "キーの種類",
"sessionExpired": "セッションの有効期間超過",
"accountKeyType": "の種類",
"sessionExpired": "セッションが失効しました",
"@sessionExpired": {
"description": "Title of the dialog when the users current session is invalid/expired"
},
"pleaseLoginAgain": "再度ログインしてください",
"loggingOut": "ログアウト中...",
"timeBasedKeyType": "時間ベース (TOTP)",
"counterBasedKeyType": "カウンタベース (HOTP)",
"counterBasedKeyType": "カウンタベース (HOTP)",
"saveAction": "保存",
"nextTotpTitle": "次へ",
"deleteCodeTitle": "コードを削除しますか?",
"deleteCodeMessage": "このコードを削除してもよろしいですか? このアクションは元に戻せません。",
"deleteCodeTitle": "コードを削除しますか",
"deleteCodeMessage": "本当にこのコードを削除してもよろしいですか?この決定は元に戻せません。",
"viewLogsAction": "ログの表示",
"sendLogsDescription": "問題のデバッグに役立つログが送信されます。機密情報が記録されないように予防措置を講じていますが、共有する前にこれらのログを確認することをお勧めします。",
"preparingLogsTitle": "ログを準備中...",
@@ -40,7 +45,7 @@
}
},
"copyEmailAction": "メールをコピー",
"exportLogsAction": "ログエクスポート",
"exportLogsAction": "ログエクスポート",
"reportABug": "バグを報告",
"crashAndErrorReporting": "クラッシュとエラーの報告",
"reportBug": "バグを報告",
@@ -53,25 +58,41 @@
}
},
"contactSupport": "サポートに問い合わせ",
"rateUsOnStore": "{storeName} で評価",
"blog": "ブログ",
"merchandise": "グッズ",
"verifyPassword": "パスワードを確認",
"pleaseWait": "お待ちください...",
"generatingEncryptionKeysTitle": "暗号化キーを生成中...",
"recreatePassword": "パスワードを再設定",
"recreatePasswordMessage": "現在のデバイスは、パスワードを確認するのに十分ではありません。全てのデバイスで利用できるように再生成する必要があります。\n\nリカバリーキーを使用してログインし、パスワードを再生成してください (ご希望の場合は再度同じパスワードを使用できます)",
"generatingEncryptionKeysTitle": "暗号化を生成中...",
"recreatePassword": "パスワードを再作成",
"recreatePasswordMessage": "現在のデバイスは、パスワードを確認するのに十分ではありません。全てのデバイスで利用できるように再生成する必要があります。\n\n回復キーを使用してログインし、パスワードを再生成してください (ご希望の場合は再度同じパスワードを使用できます)",
"useRecoveryKey": "回復キーを使用",
"incorrectPasswordTitle": "パスワードが正しくありません",
"welcomeBack": "おかえりなさい!",
"welcomeBack": "おかえりなさい",
"madeWithLoveAtPrefix": "made with ❤️ at ",
"supportDevs": "プロジェクト支援のために <bold-green>ente</bold-green> に登録",
"supportDiscount": "クーポンコード \"AUTH\" 使用すると、初年度が10%オフになります。",
"supportDiscount": "クーポンコード \"AUTH\" 使用初年度が 10% オフに",
"changeEmail": "メールアドレスを変更",
"changePassword": "パスワードを変更",
"data": "データ",
"importCodes": "コードをインポート",
"importTypePlainText": "プレーンテキスト",
"importTypeEnteEncrypted": "ente 暗号化エクスポート",
"passwordForDecryptingExport": "復号化用パスワード",
"passwordEmptyError": "パスワードは空欄にできません",
"importFromApp": "{appName} からコードをインポート",
"importGoogleAuthGuide": "Google Authenticator の \"アカウントを転送\" オプションを使用してあなたのアカウントを QR コードにエクスポートしてください。その後、他のデバイスで QR コードを読み取ってください。\n\nヒント: ノートパソコンのウェブカメラを使用して QR コードを撮影することができます。",
"importSelectJsonFile": "JSON ファイルを選択",
"importEnteEncGuide": "ente からエクスポートされた暗号化 JSON ファイルを選択",
"importRaivoGuide": "Raivo の設定の \"OTP を zip アーカイブにエクスポート\" を使用してください。\n\nzip ファイルを解凍し JSON ファイルをインポートしてください。",
"importAegisGuide": "Aegis の設定の \"保管庫をエクスポート\" を使用してください。\n\n保管庫が暗号化されている場合、保管庫を復号するためにパスワードの入力が必要になります。",
"exportCodes": "コードをエクスポート",
"importInstruction": "以下のフォーマットで、コードのリストを含むファイルを選択してください",
"importLabel": "インポート",
"importInstruction": "以下の形式のコードのリストを含むファイルを選択してください",
"importCodeDelimiterInfo": "コードはカンマまたは改行で区切ることができます",
"selectFile": "ファイルを選択",
"emailVerificationToggle": "メール認証",
"authToChangeEmailVerificationSetting": "メール認証を変更するためには認証が必要です",
"authToViewYourRecoveryKey": "回復キーを表示するためには認証が必要です",
"authToChangeYourEmail": "メールアドレスを変更するためには認証が必要です",
"authToChangeYourPassword": "パスワードを変更するためには認証が必要です",
@@ -79,8 +100,9 @@
"cancel": "キャンセル",
"yes": "はい",
"no": "いいえ",
"email": "Eメール",
"email": "E メール",
"support": "サポート",
"general": "一般",
"settings": "設定",
"copied": "コピーしました",
"pleaseTryAgain": "再度お試しください",
@@ -90,6 +112,12 @@
"enterYourPasswordHint": "パスワードを入力してください",
"forgotPassword": "パスワードを忘れた場合",
"oops": "おっと",
"suggestFeatures": "機能を提案",
"faq": "FAQ",
"faq_q_1": "ente Auth はどのくらい安全ですか?",
"faq_a_1": "ente でバックアップされたすべてのコードはエンドツーエンドで暗号化されて保管されます。これはあなただけがコードにアクセスできることを意味します。私たちのアプリはオープンソースであり、私たちの暗号は外部有識者によって検証済みです。",
"faq_q_2": "パソコンから私のコードにアクセスできますか?",
"faq_a_2": "auth.ente.io で Web からコードにアクセス可能です。",
"somethingWentWrongMessage": "問題が発生しました、再試行してください",
"leaveFamily": "ファミリーから退会",
"leaveFamilyMessage": "本当にファミリープランを退会しますか?",
@@ -122,8 +150,6 @@
"yesSendFeedbackAction": "はい、フィードバックを送信します",
"noDeleteAccountAction": "いいえ、アカウントを削除します",
"initiateAccountDeleteTitle": "アカウント削除を開始するには認証してください",
"confirmAccountDeleteTitle": "本当に ente アカウントを削除してよろしいですか?",
"confirmAccountDeleteMessage": "アップロードされたデータは、すべてのアプリ(写真と認証アプリの両方) で削除がスケジュールされます。アカウントは完全に削除されます。",
"sendEmail": "メール送信",
"createNewAccount": "新規アカウント作成",
"weakStrength": "脆弱",
@@ -263,5 +289,8 @@
"thisWillLogYouOutOfTheFollowingDevice": "以下のデバイスからログアウトします:",
"terminateSession": "セッションを終了しますか?",
"terminate": "終了",
"thisDevice": "このデバイス"
"thisDevice": "このデバイス",
"editCodeAuthMessage": "コードを編集するには認証が必要です",
"deleteCodeAuthMessage": "コードを削除するには認証が必要です",
"showQRAuthMessage": "QRコードを表示するには認証が必要です"
}

116
lib/l10n/arb/app_ka.arb Normal file
View File

@@ -0,0 +1,116 @@
{
"account": "ანგარიში",
"unlock": "განბლოკვა",
"recoveryKey": "აღდგენის კოდი",
"counterAppBarTitle": "მრიცხველზე დაფუძნებული",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "შექმენით თქვენი ორმხრივი აუთენთიფიკაციის კოდების სარეზერვო ასლი უსაფრთხოდ",
"onBoardingGetStarted": "დაწყება",
"setupFirstAccount": "დააყენეთ თქვენი პირველი ანგარიში",
"importScanQrCode": "QR კოდის დასკანერება",
"qrCode": "QR კოდი",
"importEnterSetupKey": "შეიყვანეთ დაყენების კოდი",
"importAccountPageTitle": "შეიყვანეთ ანგარიშის მონაცემები",
"secretCanNotBeEmpty": "გასაღების ველი არ შეიძლება ცარიელი იყოს",
"bothIssuerAndAccountCanNotBeEmpty": "მომწოდებლისა და ანგარიშის ველი არ შეიძლება ცარიელი იყოს",
"incorrectDetails": "არასწორი მონაცემები",
"pleaseVerifyDetails": "გთხოვთ, გადაამოწმოთ მონაცემები და სცადოთ ხელახლა",
"codeIssuerHint": "მომწოდებელი",
"codeSecretKeyHint": "გასაღები",
"codeAccountHint": "ანგარიში (you@domain.com)",
"accountKeyType": "გასაღების ტიპი",
"sessionExpired": "სესიის დრო ამოიწურა",
"@sessionExpired": {
"description": "Title of the dialog when the users current session is invalid/expired"
},
"pleaseLoginAgain": "გთხოვთ, გაიაროთ ავტორიზაცია ხელახლა",
"loggingOut": "მიმდინარეობს გამოსვლა...",
"timeBasedKeyType": "დროზე დაფუძნებული (TOTP)",
"counterBasedKeyType": "მრიცხველზე დაფუძნებული (HOTP)",
"saveAction": "შენახვა",
"nextTotpTitle": "შემდეგი",
"deleteCodeTitle": "გსურთ კოდის წაშლა?",
"deleteCodeMessage": "დარწმუნებული ხართ რომ გსურთ ამ კოდის წაშლა? ამ მოქმედების გაუქმება შეუძლებელია.",
"viewLogsAction": "აღრიცხვის ფაილების ნახვა",
"sendLogsDescription": "თქვენი პრობლემის აღმოსაფხვრელად, ეს ქმედება გააგზავნის აღრიცხვის ფაილებს. მიუხედავად იმისა, რომ ჩვენ ვიღებთ უსაფრთხოების ზომებს, რათა სენსიტიური ინფორმაცია არ მოხვდეს აღრიცხვის ფაილებში, გაგზავნამდე, გირჩევთ, გადახედოთ აღრიცხვის ფაილებს.",
"preparingLogsTitle": "მიმდინარეობს აღრიცხვის ფაილების მზადება...",
"emailLogsTitle": "აღრიცხვის ფაილების ელექტრონული ფოსტით გაგზავნა",
"emailLogsMessage": "გთხოვთ, გამოაგზავნოთ აღრიცხვის ფაილები {email}-ზე",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "ელექტრონული ფოსტის დაკოპირება",
"exportLogsAction": "აღრიცხვის ფაილების ექსპორტირება",
"reportABug": "პრობლემის შესახებ შეტყობინება",
"crashAndErrorReporting": "აპლიკაციის ხარვეზის & პრობლემის შეტყობინება",
"reportBug": "პრობლემის შეტყობინება",
"emailUsMessage": "გთხოვთ, მოგვწეროთ ელექტრონულ ფოსტაზე {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "მხარდაჭერის გუნდთან დაკავშირება",
"rateUsOnStore": "შეგვაფასეთ {storeName}-ზე",
"blog": "ბლოგი",
"merchandise": "მერჩანტი",
"verifyPassword": "პაროლის დასტური",
"pleaseWait": "გთხოვთ, დაელოდოთ...",
"generatingEncryptionKeysTitle": "მიმდინარეობს დაშიფრვის გასაღებების გენერირება...",
"recreatePassword": "პაროლის ხელახლა შექმნა",
"incorrectPasswordTitle": "არასწორი პაროლი",
"welcomeBack": "კეთილი იყოს თქვენი დაბრუნება!",
"madeWithLoveAtPrefix": "შეიქმნა ❤️ ",
"changeEmail": "ელექტრონული ფოსტის შეცვლა",
"changePassword": "პაროლის შეცვლა",
"data": "მონაცემები",
"importCodes": "კოდების იმპორტირება",
"importTypePlainText": "სტანდარტული ტექსტი",
"importTypeEnteEncrypted": "ente დაშიფრული ექსპორტი",
"passwordForDecryptingExport": "ექსპორტის გაშიფრვის პაროლი",
"passwordEmptyError": "პაროლის ველი არ შეიძლება იყოს ცარიელი",
"emailVerificationToggle": "ელექტრონული ფოსტის ვერიფიკაცია",
"cancel": "გაუქმება",
"yes": "დიახ",
"no": "არა",
"email": "ელექტრონული ფოსტა",
"support": "მხარდაჭერა",
"general": "ზოგადი",
"settings": "პარამეტრები",
"copied": "დაკოპირებულია",
"pleaseTryAgain": "გთხოვთ, სცადოთ ხელახლა",
"existingUser": "არსებული მომხმარებელი",
"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": "ჩვენ არ ვაკონტროლებთ აპლიკაციის ინსტალაციას. სასარგებლო იქნებოდა, თუ გვეტყოდით, სად გვიპოვეთ!"
}

View File

@@ -1,5 +1,6 @@
{
"account": "Account",
"unlock": "Ontgrendelen",
"recoveryKey": "Herstelsleutel",
"counterAppBarTitle": "Teller",
"@counterAppBarTitle": {
@@ -83,19 +84,25 @@
"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",
"importCodeDelimiterInfo": "De codes mogen gescheiden worden door een komma of een nieuwe regel",
"selectFile": "Bestand selecteren",
"emailVerificationToggle": "E-mailverificatie",
"emailVerificationEnableWarning": "Als u de 2FA van uw e-mail bij ons opslaat, kan de verificatie van die e-mail resulteren in een riskante impasse. Als u bent uitgesloten van een van beide diensten, kunt u zich mogelijk niet meer aanmelden bij de andere.",
"authToChangeEmailVerificationSetting": "Gelieve te verifiëren om de e-mailverificatie te wijzigen",
"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",
@@ -156,8 +163,6 @@
"yesSendFeedbackAction": "Ja, geef feedback",
"noDeleteAccountAction": "Nee, verwijder account",
"initiateAccountDeleteTitle": "Gelieve te verifiëren om het account te verwijderen",
"confirmAccountDeleteTitle": "Weet je zeker dat je je ente account wil verwijderen?",
"confirmAccountDeleteMessage": "Uw geüploade gegevens, in alle apps (Photos en Authenticator), worden ingepland voor verwijdering en uw account zal permanent worden verwijderd.",
"sendEmail": "E-mail versturen",
"createNewAccount": "Nieuw account aanmaken",
"weakStrength": "Zwak",
@@ -329,5 +334,74 @@
"sigInBackupReminder": "Exporteer de codes zodat je een back-up hebt waarvandaan je kan herstellen.",
"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",
"focusOnSearchBar": "Focus zoekveld na starten app"
"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",
"editCodeAuthMessage": "Authenticeren om code te bewerken",
"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.",
"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!"
}

View File

@@ -1,5 +1,6 @@
{
"account": "Konto",
"unlock": "Odblokuj",
"recoveryKey": "Klucz odzyskiwania",
"counterAppBarTitle": "Licznik",
"@counterAppBarTitle": {
@@ -9,8 +10,13 @@
"onBoardingGetStarted": "Wprowadzenie",
"setupFirstAccount": "Skonfiguruj pierwsze konto",
"importScanQrCode": "Zeskanuj kod QR",
"qrCode": "Kod QR",
"importEnterSetupKey": "Wprowadź klucz",
"importAccountPageTitle": "Wprowadź dane konta",
"secretCanNotBeEmpty": "Sekret nie może być pusty",
"bothIssuerAndAccountCanNotBeEmpty": "Pola wydawca i konto nie mogą być puste",
"incorrectDetails": "Nieprawidłowe szczegóły",
"pleaseVerifyDetails": "Proszę zweryfikować szczegóły i spróbuj ponownie",
"codeIssuerHint": "Wydawca",
"codeSecretKeyHint": "Tajny klucz",
"codeAccountHint": "Konto (ty@domena.com)",
@@ -53,6 +59,9 @@
}
},
"contactSupport": "Skontaktuj się z pomocą techniczną",
"rateUsOnStore": "Oceń nas na {storeName}",
"blog": "Blog",
"merchandise": "Sklep",
"verifyPassword": "Zweryfikuj hasło",
"pleaseWait": "Proszę czekać...",
"generatingEncryptionKeysTitle": "Generowanie kluczy szyfrujących...",
@@ -68,19 +77,35 @@
"changePassword": "Zmień hasło",
"data": "Dane",
"importCodes": "Importuj kody",
"importTypePlainText": "Zwykły tekst",
"importTypeEnteEncrypted": "Zaszyfrowany eksport ente",
"passwordForDecryptingExport": "Hasło do odszyfrowania eksportu",
"passwordEmptyError": "Pole hasło nie może być puste",
"importFromApp": "Importuj kody z {appName}",
"importGoogleAuthGuide": "Wyeksportuj twoje konta z Google Authenticator do kodu QR używając opcji \"Przenieś konta\". Potem używając innego urządzenia, zeskanuj kod QR.",
"importSelectJsonFile": "Wybierz plik JSON",
"importEnteEncGuide": "Wybierz zaszyfrowany plik JSON wyeksportowany z ente",
"importRaivoGuide": "Użyj opcji \"Eksportuj OTP do archiwum ZIP\" w Ustawieniach Raivo.\n\nWyodrębnij plik zip i zaimportuj plik JSON.",
"importAegisGuide": "Użyj opcji \"Eksportuj sejf\" w ustawieniach Aegis.\n\nJeśli twój sejf jest zaszyfrowany, musisz wprowadzić hasło sejfu, aby odszyfrować sejf.",
"exportCodes": "Eksportuj kody",
"importLabel": "Importuj",
"importInstruction": "Wybierz plik, który zawiera listę twoich kodów w następującym formacie",
"importCodeDelimiterInfo": "Kody mogą być oddzielone przecinkiem lub nową linią",
"selectFile": "Wybierz plik",
"emailVerificationToggle": "Weryfikacja e-mail",
"emailVerificationEnableWarning": "Jeśli przechowujesz uwierzytelnianie dwuskładnikowe do twojego e-mailu z nami, włączenie weryfikacji adresu e-mail może spowodować impas. Jeśli jesteś zablokowany z jednej usługi, możesz nie być w stanie zalogować się do drugiej.",
"authToChangeEmailVerificationSetting": "Proszę uwierzytelnić, aby zmienić weryfikację e-mail",
"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",
"no": "Nie",
"email": "Email",
"support": "Wsparcie techniczne",
"general": "Ogólne",
"settings": "Ustawienia",
"copied": "Skopiowano",
"pleaseTryAgain": "Proszę spróbować ponownie",
@@ -90,6 +115,18 @@
"enterYourPasswordHint": "Wprowadź swoje hasło",
"forgotPassword": "Nie pamiętam hasła",
"oops": "Ups",
"suggestFeatures": "Zaproponuj funkcje",
"faq": "Najczęściej zadawane pytania (FAQ)",
"faq_q_1": "Jak bezpieczny jest ente Auth?",
"faq_a_1": "Wszystkie kody, których tworzysz kopię zapasową za pomocą ente są przechowywane zaszyfrowane end-to-end. Oznacza to, że tylko Ty możesz uzyskać dostęp do swoich kodów. Nasze aplikacje są otwarto-źródłowe, a nasza kryptografia została poddana sprawdzeniu z zewnątrz.",
"faq_q_2": "Czy mogę uzyskać dostęp do moich kodów na komputerze?",
"faq_a_2": "Możesz uzyskać dostęp do swoich kodów na stronie auth.ente.io.",
"faq_q_3": "Jak mogę usunąć kody?",
"faq_a_3": "Możesz usunąć kod, przesuwając go w lewo.",
"faq_q_4": "Jak mogę wesprzeć ten projekt?",
"faq_a_4": "Możesz wspierać rozwój tego projektu, subskrybując do naszej aplikacji Zdjęcia na ente.io.",
"faq_q_5": "Jak mogę włączyć blokadę FaceID w ente Auth?",
"faq_a_5": "Możesz włączyć blokadę FaceID w Ustawienia → Bezpieczeństwo→ Ekran blokady.",
"somethingWentWrongMessage": "Coś poszło nie tak. Proszę, spróbuj ponownie",
"leaveFamily": "Opuść rodzinę",
"leaveFamilyMessage": "Czy jesteś pewien/pewna, że chcesz opuścić plan rodzinny?",
@@ -122,8 +159,6 @@
"yesSendFeedbackAction": "Tak, wyślij opinię",
"noDeleteAccountAction": "Nie, usuń moje konto",
"initiateAccountDeleteTitle": "Proszę uwierzytelnić, aby zainicjować usuwanie konta",
"confirmAccountDeleteTitle": "Na pewno chcesz usunąć swoje konto ente?",
"confirmAccountDeleteMessage": "Twoje przesłane dane, we wszystkich aplikacjach (zarówno Zdjęcia, jak i Authenticator), zostaną zaplanowane do usunięcia, a Twoje konto zostanie trwale usunięte.",
"sendEmail": "Wyślij e-mail",
"createNewAccount": "Utwórz nowe konto",
"weakStrength": "Słabe",
@@ -150,12 +185,14 @@
"enterDetailsManually": "Wprowadź dane ręcznie",
"edit": "Edytuj",
"copiedToClipboard": "Skopiowano do schowka",
"copiedNextToClipboard": "Skopiowano następny kod do schowka",
"error": "Błąd",
"recoveryKeyCopiedToClipboard": "Klucz odzyskiwania został skopiowany do schowka",
"recoveryKeyOnForgotPassword": "Jeśli zapomnisz hasła, jedynym sposobem na odzyskanie danych jest ten klucz.",
"recoveryKeySaveDescription": "Nie przechowujemy tego klucza, proszę zachować ten 24 wyrazowy klucz w bezpiecznym miejscu.",
"doThisLater": "Zrób To Później",
"saveKey": "Zapisz klucz",
"back": "Wstecz",
"createAccount": "Utwórz konto",
"passwordStrength": "Siła hasła: {passwordStrengthValue}",
"@passwordStrength": {
@@ -219,6 +256,10 @@
"privacy": "Prywatność",
"terms": "Warunki",
"checkForUpdates": "Sprawdź czy są dostępne nowe aktualizacje",
"downloadUpdate": "Pobierz",
"criticalUpdateAvailable": "Dostępna jest krytyczna aktualizacja",
"updateAvailable": "Dostępna jest aktualizacja",
"update": "Aktualizuj",
"checking": "Sprawdzanie...",
"youAreOnTheLatestVersion": "Używasz najnowszej wersji",
"warning": "Ostrzeżenie",
@@ -263,5 +304,39 @@
"thisWillLogYouOutOfTheFollowingDevice": "To wyloguje Cię z tego urządzenia:",
"terminateSession": "Zakończyć sesję?",
"terminate": "Zakończ",
"thisDevice": "To urządzenie"
"thisDevice": "To urządzenie",
"toResetVerifyEmail": "Aby zresetować hasło, najpierw zweryfikuj swój e-mail.",
"thisEmailIsAlreadyInUse": "Ten adres e-mail już jest zajęty",
"verificationFailedPleaseTryAgain": "Weryfikacja nie powiodła się, spróbuj ponownie",
"yourVerificationCodeHasExpired": "Twój kod weryfikacyjny wygasł",
"incorrectCode": "Nieprawidłowy kod",
"sorryTheCodeYouveEnteredIsIncorrect": "Niestety, wprowadzony kod jest nieprawidłowy",
"emailChangedTo": "Adres e-mail został zmieniony na {newEmail}",
"authenticationFailedPleaseTryAgain": "Uwierzytelnianie nie powiodło się, proszę spróbować ponownie",
"authenticationSuccessful": "Uwierzytelnianie powiodło się!",
"twofactorAuthenticationSuccessfullyReset": "Pomyślnie zresetowano uwierzytelnianie dwuskładnikowe",
"incorrectRecoveryKey": "Nieprawidłowy klucz odzyskiwania",
"theRecoveryKeyYouEnteredIsIncorrect": "Wprowadzony klucz odzyskiwania jest nieprawidłowy",
"enterPassword": "Wprowadź hasło",
"selectExportFormat": "Wybierz format eksportu",
"exportDialogDesc": "Zaszyfrowane eksporty będą chronione przez wybrane przez Ciebie hasło.",
"encrypted": "Zaszyfrowane",
"plainText": "Zwykły tekst",
"passwordToEncryptExport": "Hasło do odszyfrowania eksportu",
"export": "Eksportuj",
"useOffline": "Używaj bez kopii zapasowych",
"signInToBackup": "Zaloguj się, aby wykonać kopię zapasową swoich kodów",
"singIn": "Zaloguj się",
"sigInBackupReminder": "Proszę wyeksportować swoje kody, aby upewnić się, że masz kopię zapasową, z której możesz przywrócić swoje kody.",
"offlineModeWarning": "Wybrałeś kontynuację bez kopii zapasowych. Proszę wykonywać ręczne kopie zapasowe, aby upewnić się, że Twoje kody są bezpieczne.",
"showLargeIcons": "Pokaż duże ikony",
"shouldHideCode": "Ukryj kody",
"focusOnSearchBar": "Uaktywnij wyszukiwanie przy uruchamianiu aplikacji",
"confirmUpdatingkey": "Czy na pewno chcesz zaktualizować tajny klucz?",
"minimizeAppOnCopy": "Minimalizuj aplikację przy kopiowaniu",
"editCodeAuthMessage": "Uwierzytelnij, aby edytować kod",
"deleteCodeAuthMessage": "Uwierzytelnij, aby usunąć kod",
"showQRAuthMessage": "Uwierzytelnij, aby pokazać kod QR",
"confirmAccountDeleteTitle": "Potwierdź usunięcie konta",
"confirmAccountDeleteMessage": "To konto jest połączone z innymi aplikacjami ente, jeśli ich używasz.\n\nTwoje przesłane dane, we wszystkich aplikacjach ente, zostaną zaplanowane do usunięcia, a Twoje konto zostanie trwale usunięte."
}

View File

@@ -120,8 +120,6 @@
"yesSendFeedbackAction": "Sim, enviar feedback",
"noDeleteAccountAction": "Não, excluir conta",
"initiateAccountDeleteTitle": "Por favor, autentique-se para iniciar a exclusão de conta",
"confirmAccountDeleteTitle": "Tem certeza que deseja excluir sua conta ente?",
"confirmAccountDeleteMessage": "Seus dados enviados, através de todos os aplicativos (Photos e Authenticator), serão agendados para exclusão, e sua conta será permanentemente deletada.",
"sendEmail": "Enviar e-mail",
"createNewAccount": "Criar nova conta",
"weakStrength": "Fraca",
@@ -223,5 +221,8 @@
"sorry": "Desculpe",
"importFailureDesc": "Não foi possível analisar o arquivo selecionado.\nPor favor, escreva para support@ente.io se precisar de ajuda!",
"pendingSyncs": "Atenção",
"pendingSyncsWarningBody": "Alguns de seus códigos não foram salvos.\n\nPor favor, certifique-se que você possui um backup para esses códigos antes de sair."
"pendingSyncsWarningBody": "Alguns de seus códigos não foram salvos.\n\nPor favor, certifique-se que você possui um backup para esses códigos antes de sair.",
"editCodeAuthMessage": "Autenticar para editar o código",
"deleteCodeAuthMessage": "Autenticar para excluir o código",
"showQRAuthMessage": "Autenticar para mostrar o QR Code"
}

View File

@@ -1,5 +1,6 @@
{
"account": "Аккаунт",
"unlock": "Разблокировать",
"recoveryKey": "Ключ восстановления",
"counterAppBarTitle": "Счетчик",
"@counterAppBarTitle": {
@@ -85,6 +86,7 @@
"importSelectJsonFile": "Выбрать JSON-файл",
"importEnteEncGuide": "Выберите зашифрованный JSON-файл, экспортированный из ente",
"importRaivoGuide": "Используйте опцию «Export OTPs to Zip archive» в настройках Raivo.\n\nРаспакуйте zip-архив и импортируйте JSON-файл.",
"importBitwardenGuide": "Используйте опцию \"Экспортировать хранилище\" в Bitwarden Tools и импортируйте незашифрованный JSON файл.",
"importAegisGuide": "Используйте опцию «Экспортировать хранилище» в настройках Aegis.\n\nЕсли ваше хранилище зашифровано, то для его расшифровки потребуется ввести пароль хранилища.",
"exportCodes": "Экспортировать коды",
"importLabel": "Импорт",
@@ -92,16 +94,19 @@
"importCodeDelimiterInfo": "Коды могут быть разделены запятой или новой строкой",
"selectFile": "Выбрать файл",
"emailVerificationToggle": "Подтверждение электронной почты",
"emailVerificationEnableWarning": "Если вы храните у нас двухфакторную аутентификацию в своей электронной почте, включение проверки электронной почты может привести к тупиковой ситуации. Если у вас заблокирован доступ к одной службе, возможно, вы не сможете войти в другую.",
"authToChangeEmailVerificationSetting": "Авторизуйтесь, чтобы изменить подтверждение электронной почты",
"authToViewYourRecoveryKey": "Пожалуйста, авторизуйтесь для просмотра вашего ключа восстановления",
"authToChangeYourEmail": "Пожалуйста, авторизуйтесь, чтобы изменить адрес электронной почты",
"authToChangeYourPassword": "Пожалуйста, авторизуйтесь, чтобы изменить пароль",
"authToViewSecrets": "Пожалуйста, авторизуйтесь для просмотра ваших секретов",
"ok": "Ок",
"cancel": "Отменить",
"yes": "Да",
"no": "Нет",
"email": "Электронная почта",
"support": "Поддержка",
"general": "Общие",
"settings": "Настройки",
"copied": "Скопировано",
"pleaseTryAgain": "Пожалуйста, попробуйте ещё раз",
@@ -155,8 +160,6 @@
"yesSendFeedbackAction": "Да, отправить отзыв",
"noDeleteAccountAction": "Нет, удалить аккаунт",
"initiateAccountDeleteTitle": "Пожалуйста, авторизуйтесь, чтобы начать удаление аккаунта",
"confirmAccountDeleteTitle": "Вы уверены, что хотите удалить ваш аккаунт ente?",
"confirmAccountDeleteMessage": "Ваши загруженные данные во всех приложениях (как фотографии, так и средство аутентификации) будут запланированы к удалению, а ваш аккаунт будет удален безвозвратно.",
"sendEmail": "Отправить электронное письмо",
"createNewAccount": "Создать новый аккаунт",
"weakStrength": "Слабый",
@@ -183,6 +186,7 @@
"enterDetailsManually": "Ввести детали вручную",
"edit": "Редактировать",
"copiedToClipboard": "Скопировано",
"copiedNextToClipboard": "Следующий код скопирован в буфер обмена",
"error": "Ошибка",
"recoveryKeyCopiedToClipboard": "Ключ восстановления скопирован в буфер обмена",
"recoveryKeyOnForgotPassword": "Если вы забыли свой пароль, то восстановить данные можно только с помощью этого ключа.",
@@ -253,6 +257,10 @@
"privacy": "Конфиденциальность",
"terms": "Условия использования",
"checkForUpdates": "Проверить наличие обновлений",
"downloadUpdate": "Скачать",
"criticalUpdateAvailable": "Доступно критическое обновление",
"updateAvailable": "Доступно обновление",
"update": "Обновить",
"checking": "Проверка...",
"youAreOnTheLatestVersion": "Вы используете последнюю версию",
"warning": "Предупреждение",
@@ -316,5 +324,74 @@
"encrypted": "Зашифрованный",
"plainText": "Обычный текст",
"passwordToEncryptExport": "Пароль для шифрования экспорта",
"export": "Экспорт"
"export": "Экспорт",
"useOffline": "Использовать без резервных копий",
"signInToBackup": "Войдите в систему, чтобы создать резервную копию своих кодов",
"singIn": "Войти",
"sigInBackupReminder": "Экспортируйте свои коды, чтобы убедиться, что у вас есть резервная копия, из которой можно восстановить.",
"offlineModeWarning": "Вы решили продолжить без резервных копий. Пожалуйста, создайте резервные копии вручную, чтобы убедиться, что ваши коды в безопасности.",
"showLargeIcons": "Показать большие значки",
"shouldHideCode": "Скрыть коды",
"focusOnSearchBar": "Фокусировать поиск при запуске приложения",
"confirmUpdatingkey": "Вы уверены, что хотите обновить секретный ключ?",
"minimizeAppOnCopy": "Свернуть приложение при копировании",
"editCodeAuthMessage": "Аутентификация для редактирования кода",
"deleteCodeAuthMessage": "Аутентификация для удаления кода",
"showQRAuthMessage": "Аутентификация для отображения QR-кода",
"confirmAccountDeleteTitle": "Подтвердить удаление аккаунта",
"confirmAccountDeleteMessage": "Эта учетная запись связана с другими приложениями ente, если вы ими пользуетесь.\n\nЗагруженные вами данные во всех приложениях ente будут запланированы к удалению, а ваша учетная запись будет удалена без возможности восстановления.",
"androidBiometricHint": "Подтвердите личность",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
},
"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."
},
"androidBiometricRequiredTitle": "Требуется биометрия",
"@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": "Требуются учетные данные устройства",
"@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": "Требуются учетные данные устройства",
"@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": "Перейдите к настройкам",
"@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": "Биометрическая аутентификация не настроена на вашем устройстве. Перейдите в \"Настройки > Безопасность\", чтобы добавить биометрическую аутентификацию.",
"@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": "Биометрическая аутентификация отключена. Пожалуйста, заблокируйте и разблокируйте экран, чтобы включить ее.",
"@iOSLockOut": {
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
},
"iOSGoToSettingsDescription": "Биометрическая аутентификация не настроена на вашем устройстве. Пожалуйста, включите Touch ID или Face ID на вашем телефоне.",
"@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": "ОК",
"@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": "Нет подключения к Интернету",
"pleaseCheckYourInternetConnectionAndTryAgain": "Проверьте подключение к Интернету и повторите попытку."
}

View File

@@ -1,5 +1,6 @@
{
"account": "Hesabım",
"unlock": "Kilidi aç",
"recoveryKey": "Kurtarma Anahtarı",
"counterAppBarTitle": "Sayaç",
"@counterAppBarTitle": {
@@ -83,6 +84,7 @@
"importSelectJsonFile": "JSON dosyasını seçin",
"importEnteEncGuide": "Ente'den dışa aktarılan şifrelenmiş JSON dosyasını seçin",
"importRaivoGuide": "Raivo'nun ayarlarında \"OTP'leri Zip arşivine aktar\" seçeneğini kullanın.\n\nZip dosyasını çıkarın ve JSON dosyasını içe aktarın.",
"importBitwardenGuide": "Bitwarden Tools içindeki \"Kasayı dışa aktar\" seçeneğini kullanın ve şifrelenmemiş JSON dosyasını içe aktarın.",
"importAegisGuide": "Aegis'in Ayarlarında \"Kasayı dışa aktar\" seçeneğini kullanın.\n\nKasanız şifrelenmişse, kasanın şifresini çözmek için kasa parolasını girmeniz gerekecektir.",
"exportCodes": "Kodu dışa aktar",
"importLabel": "İçe aktar",
@@ -90,16 +92,19 @@
"importCodeDelimiterInfo": "Kodlar, virgülle ya da yeni bir satırla ayrılabilir",
"selectFile": "Dosya seç",
"emailVerificationToggle": "E-posta doğrulama",
"emailVerificationEnableWarning": "E-postanız için 2FA'yı bizde saklıyorsanız, e-posta doğrulamasını açmak bir kilitlenmeye neden olabilir. Bir hizmetin dışında kalırsanız, diğerine giriş yapamayabilirsiniz.",
"authToChangeEmailVerificationSetting": "E-posta doğrulamasını değiştirmek için lütfen kimlik doğrulaması yapın",
"authToViewYourRecoveryKey": "Kurtarma anahtarınızı görmek için lütfen kimliğinizi doğrulayın",
"authToChangeYourEmail": "Epostanızı değiştirmek için lütfen kimliğinizi doğrulayın",
"authToChangeYourPassword": "Şifrenizi değiştirmek için lütfen kimliğinizi doğrulayın",
"authToInitiateSignIn": "Yedekleme için giriş yapmayı başlatmak üzere lütfen kimlik doğrulaması yapın.",
"ok": "Tamam",
"cancel": "İptal Et",
"yes": "Evet",
"no": "Hayır",
"email": "E-Posta",
"support": "Destek",
"general": "Genel",
"settings": "Ayarlar",
"copied": "Kopyalandı",
"pleaseTryAgain": "Lütfen tekrar deneyin",
@@ -153,8 +158,6 @@
"yesSendFeedbackAction": "Evet, geri bildirimi gönder",
"noDeleteAccountAction": "Hayır, hesabı sil",
"initiateAccountDeleteTitle": "Hesap silme işlemini yapabilmek için lütfen kimliğinizi doğrulayın",
"confirmAccountDeleteTitle": "ente hesabınızı silmek istediğinizden emin misiniz?",
"confirmAccountDeleteMessage": "Tüm uygulamalarda (Fotoğraflar ve Kimlik doğrulayıcı) kaydedilen verileriniz zamanlı silinmeye ayarlanacak ve hesabınız kalıcı olarak silinecektir.",
"sendEmail": "E-posta gönder",
"createNewAccount": "Yeni hesap oluşturun",
"weakStrength": "Zayıf",
@@ -181,6 +184,7 @@
"enterDetailsManually": "Bilgileri elle girin",
"edit": "Düzenle",
"copiedToClipboard": "Panoya kopyalandı",
"copiedNextToClipboard": "Sonraki kod panoya kopyalandı",
"error": "Hata",
"recoveryKeyCopiedToClipboard": "Kurtarma anahtarı panoya kopyalandı",
"recoveryKeyOnForgotPassword": "Eğer şifrenizi unutursanız, verilerinizi kurtarabileceğiniz tek yol bu anahtardır.",
@@ -251,6 +255,10 @@
"privacy": "Gizlilik",
"terms": "Şartlar",
"checkForUpdates": "Güncellemeleri denetleyin",
"downloadUpdate": "İndir",
"criticalUpdateAvailable": "Kritik güncelleme mevcut",
"updateAvailable": "Güncelleme mevcut",
"update": "Güncelle",
"checking": "Denetleniyor...",
"youAreOnTheLatestVersion": "En son sürümdesiniz",
"warning": "Uyarı",
@@ -314,5 +322,70 @@
"encrypted": "Şifreli",
"plainText": "Düz metin",
"passwordToEncryptExport": "Dışa aktarımı şifrelemek için parola",
"export": "Dışa aktar"
"export": "Dışa aktar",
"useOffline": "Yedekleme olmadan kullan",
"signInToBackup": "Kodlarınızı yedeklemek için giriş yapın",
"singIn": "Giriş yap",
"sigInBackupReminder": "Geri yükleyebileceğiniz bir yedeğiniz olduğundan emin olmak için lütfen kodlarınızı dışa aktarın.",
"offlineModeWarning": "Yedekleme yapmadan devam etmeyi seçtiniz. Kodlarınızın güvende olduğundan emin olmak için lütfen manuel yedekleme yapın.",
"showLargeIcons": "Büyük simgeler göster",
"shouldHideCode": "Kodları gizle",
"doubleTapToViewHiddenCode": "Kodu görüntülemek için bir girdiye çift dokunabilirsiniz",
"focusOnSearchBar": "Uygulama başladığında arama bölümüne odaklan",
"minimizeAppOnCopy": "Kopyalarken uygulamayı küçült",
"editCodeAuthMessage": "Kodu düzenlemek için doğrulama yapın",
"deleteCodeAuthMessage": "Kodu silmek için doğrulama yapın",
"showQRAuthMessage": "QR kodunu göstermek için doğrulama yapın",
"confirmAccountDeleteTitle": "Hesap silme işlemini onayla",
"confirmAccountDeleteMessage": "Bu hesap, eğer kullanıyorsanız, diğer ente uygulamalarıyla bağlantılıdır.\n\nTüm ente uygulamalarında yüklediğiniz veriler silinmek üzere programlanacak ve hesabınız kalıcı olarak silinecektir.",
"androidBiometricHint": "Kimliği doğrula",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
},
"androidBiometricNotRecognized": "Tanınmadı. Tekrar deneyin.",
"@androidBiometricNotRecognized": {
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
},
"androidBiometricSuccess": "Başarılı",
"@androidBiometricSuccess": {
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
},
"androidCancelButton": "İptal et",
"@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": "Kimlik doğrulaması gerekli",
"@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": "Biyometrik gerekli",
"@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": "Cihaz kimlik bilgileri gerekli",
"@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."
},
"goToSettings": "Ayarlara git",
"@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": "Biyometrik kimlik doğrulama cihazınızda ayarlanmamış. Biyometrik kimlik doğrulama eklemek için 'Ayarlar > Güvenlik' bölümüne gidin.",
"@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": "Biyometrik kimlik doğrulama devre dışı. Etkinleştirmek için lütfen ekranınızı kilitleyin ve kilidini açın.",
"@iOSLockOut": {
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
},
"iOSGoToSettingsDescription": "Cihazınızda biyometrik kimlik doğrulama ayarlanmamış. Lütfen telefonunuzda Touch ID veya Face ID'yi etkinleştirin.",
"@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": "Tamam",
"@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": "İnternet bağlantısı yok",
"pleaseCheckYourInternetConnectionAndTryAgain": "Lütfen internet bağlantınızı kontrol edin ve yeniden deneyin."
}

View File

@@ -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ố 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?",
@@ -126,8 +163,6 @@
"yesSendFeedbackAction": "Có, gửi phản hồi",
"noDeleteAccountAction": "Không, xóa tài khoản",
"initiateAccountDeleteTitle": "Vui lòng xác thực để bắt đầu xóa tài khoản",
"confirmAccountDeleteTitle": "Bạn có chắc rằng bạn muốn xóa tài khoản ente của bạn không?",
"confirmAccountDeleteMessage": "Dữ liệu đã tải lên của bạn, trên tất cả các ứng dụng (cả Ảnh và Authenticator), sẽ được lên lịch xóa và tài khoản của bạn sẽ bị xóa vĩnh viễn.",
"sendEmail": "Gửi email",
"createNewAccount": "Tạo tài khoản mới",
"weakStrength": "Yếu",
@@ -154,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": {
@@ -223,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",
@@ -267,5 +308,100 @@
"thisWillLogYouOutOfTheFollowingDevice": "Thao tác này sẽ đăng xuất bạn khỏi thiết bị sau:",
"terminateSession": "Chấm dứt phiên?",
"terminate": "Dừng lại",
"thisDevice": "Thiết bị này"
"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",
"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!"
}

View File

@@ -1,5 +1,6 @@
{
"account": "账户",
"unlock": "解锁",
"recoveryKey": "恢复密钥",
"counterAppBarTitle": "计数器",
"@counterAppBarTitle": {
@@ -83,19 +84,25 @@
"importFromApp": "从 {appName} 导入代码",
"importGoogleAuthGuide": "使用“转移帐户”选项将您的帐户从 Google 身份验证器导出到二维码。然后使用另一台设备扫描二维码。\n\n提示您可以使用笔记本电脑的网络摄像头拍摄二维码的照片。",
"importSelectJsonFile": "选择 JSON 文件",
"importSelectAppExport": "选择 {appName} 的导出文件",
"importEnteEncGuide": "选择从ente导出的加密JSON文件",
"importRaivoGuide": "使用 Raivo 设置中的“将 OTP 导出到 Zip 存档”选项。\n\n解压 zip 文件并导入 JSON 文件。",
"importBitwardenGuide": "使用 Bitwarden 工具中的“导出保管库”选项并导入未加密的 JSON 文件。",
"importAegisGuide": "在Aegis的设置中使用\"导出密码库\"选项。\n\n如果您的密码库已加密您需要输入密码才能解密密码库。",
"import2FasGuide": "使用 2FAS 中的“设置 -> 备份 - 导出”选项。\n\n如果您的备份已被加密则需要输入密码才能解密备份",
"exportCodes": "导出代码",
"importLabel": "导入",
"importInstruction": "请以以下格式选择包含代码列表的文件",
"importCodeDelimiterInfo": "代码可以用逗号或新行分隔。",
"selectFile": "选择文件",
"emailVerificationToggle": "电子邮件验证",
"emailVerificationEnableWarning": "如果您将 2FA 存储到我们的电子邮件中,则打开电子邮件验证可能会导致僵局。如果您被一项服务锁定,您可能无法登录另一项服务。",
"authToChangeEmailVerificationSetting": "请进行身份验证以更改电子邮件验证",
"authToViewYourRecoveryKey": "请验证以查看您的恢复密钥",
"authToChangeYourEmail": "请验证以更改您的电子邮件",
"authToChangeYourPassword": "请验证以更改密码",
"authToViewSecrets": "请进行身份验证以查看您的秘密",
"authToInitiateSignIn": "请进行身份验证以启动登录进行备份。",
"ok": "好的",
"cancel": "取消",
"yes": "是",
@@ -156,8 +163,6 @@
"yesSendFeedbackAction": "是,发送反馈",
"noDeleteAccountAction": "不,删除账户",
"initiateAccountDeleteTitle": "请进行身份验证以启动账户删除",
"confirmAccountDeleteTitle": "确定要删除您的ente账户吗",
"confirmAccountDeleteMessage": "您上传的数据,跨越所有应用程序(Photos 和 Authenticator 两者),将被排定删除,您的账户将被永久删除。",
"sendEmail": "发送电子邮件",
"createNewAccount": "创建新账号",
"weakStrength": "弱",
@@ -329,5 +334,74 @@
"sigInBackupReminder": "请导出您的代码以确保您有可以恢复的备份。",
"offlineModeWarning": "您已选择在不进行备份的情况下继续操作。请手动备份以确保您的代码安全。",
"showLargeIcons": "显示大图标",
"focusOnSearchBar": "应用启动后聚焦搜索"
"shouldHideCode": "隐藏代码",
"doubleTapToViewHiddenCode": "您可以双击条目来查看代码",
"focusOnSearchBar": "应用启动后聚焦搜索",
"confirmUpdatingkey": "您确定要更新此密钥吗?",
"minimizeAppOnCopy": "复制时最小化应用",
"editCodeAuthMessage": "编辑代码需要身份验证",
"deleteCodeAuthMessage": "删除代码需要身份验证",
"showQRAuthMessage": "显示QR码需要身份验证",
"confirmAccountDeleteTitle": "确认删除账户",
"confirmAccountDeleteMessage": "该账户已链接到其他ente旗下的应用程序如果您使用任何相关的应用程序。\n\n您在所有ente旗下应用程序中上传的数据都将被安排删除并且您的账户将被永久删除。",
"androidBiometricHint": "验证身份",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
},
"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."
},
"androidBiometricRequiredTitle": "需要进行生物识别认证",
"@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": "需要设备凭据",
"@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": "需要设备凭据",
"@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": "前往设置",
"@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": "您的设备上未设置生物识别身份验证。转到“设置 > 安全”以添加生物识别身份验证。",
"@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": "生物识别身份验证已禁用。请锁定再解锁您的屏幕以启用它。",
"@iOSLockOut": {
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
},
"iOSGoToSettingsDescription": "您的设备上未设置生物识别身份验证。请在您的手机上启用 触控 ID 或 面容 ID。",
"@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": "好的",
"@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": "无互联网连接",
"pleaseCheckYourInternetConnectionAndTryAgain": "请检查您的互联网连接,然后重试。",
"signOutFromOtherDevices": "从其他设备退出登录",
"signOutOtherBody": "如果你认为有人可能知道你的密码,你可以强制所有使用你账户的其他设备退出登录。",
"signOutOtherDevices": "登出其他设备",
"doNotSignOut": "不要退登",
"hearUsWhereTitle": "您是如何知道Ente的 (可选的)",
"hearUsExplanation": "我们不跟踪应用程序安装情况。如果您告诉我们您是在哪里找到我们的,将会有所帮助!"
}

View File

@@ -24,7 +24,7 @@ Locale localResolutionCallBack(locales, supportedLocales) {
Locale? languageCodeMatch;
final Map<String, Locale> languageCodeToLocale = {
for (Locale supportedLocale in appSupportedLocales)
supportedLocale.languageCode: supportedLocale
supportedLocale.languageCode: supportedLocale,
};
for (Locale locale in locales) {

View File

@@ -21,8 +21,10 @@ import 'package:ente_auth/ui/utils/icon_utils.dart';
import 'package:ente_auth/utils/crypto_util.dart';
import 'package:flutter/foundation.dart';
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");
@@ -30,6 +32,23 @@ 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();
}
Future<void> _runInForeground(AdaptiveThemeMode? savedThemeMode) async {

View File

@@ -1,5 +1,7 @@
import "package:ente_auth/l10n/l10n.dart";
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
import 'package:ente_auth/ui/components/models/button_result.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/totp_util.dart';
import "package:flutter/material.dart";
@@ -10,7 +12,8 @@ class SetupEnterSecretKeyPage extends StatefulWidget {
SetupEnterSecretKeyPage({this.code, Key? key}) : super(key: key);
@override
State<SetupEnterSecretKeyPage> createState() => _SetupEnterSecretKeyPageState();
State<SetupEnterSecretKeyPage> createState() =>
_SetupEnterSecretKeyPageState();
}
class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
@@ -25,7 +28,8 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
text: widget.code != null ? safeDecode(widget.code!.issuer).trim() : null,
);
_accountController = TextEditingController(
text: widget.code != null ? safeDecode(widget.code!.account).trim() : null,
text:
widget.code != null ? safeDecode(widget.code!.account).trim() : null,
);
_secretController = TextEditingController(
text: widget.code != null ? widget.code!.secret : null,
@@ -110,7 +114,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
SizedBox(
width: 400,
child: OutlinedButton(
onPressed: () {
onPressed: () async {
if ((_accountController.text.trim().isEmpty &&
_issuerController.text.trim().isEmpty) ||
_secretController.text.trim().isEmpty) {
@@ -118,32 +122,13 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
if (_secretController.text.trim().isEmpty) {
message = context.l10n.secretCanNotBeEmpty;
} else {
message = context.l10n.bothIssuerAndAccountCanNotBeEmpty;
message =
context.l10n.bothIssuerAndAccountCanNotBeEmpty;
}
_showIncorrectDetailsDialog(context, message: message);
return;
}
try {
final account = _accountController.text.trim();
final issuer = _issuerController.text.trim();
final secret = _secretController.text.trim().replaceAll(' ', '');
final Code newCode = widget.code == null
? Code.fromAccountAndSecret(
account,
issuer,
secret,
)
: widget.code!.copyWith(
account: account,
issuer: issuer,
secret: secret,
);
// Verify the validity of the code
getOTP(newCode);
Navigator.of(context).pop(newCode);
} catch (e) {
_showIncorrectDetailsDialog(context);
}
await _saveCode();
},
child: Padding(
padding: const EdgeInsets.symmetric(
@@ -153,7 +138,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
child: Text(l10n.saveAction),
),
),
)
),
],
),
),
@@ -162,6 +147,44 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
);
}
Future<void> _saveCode() async {
try {
final account = _accountController.text.trim();
final issuer = _issuerController.text.trim();
final secret = _secretController.text.trim().replaceAll(' ', '');
if (widget.code != null && widget.code!.secret != secret) {
ButtonResult? result = await showChoiceActionSheet(
context,
title: context.l10n.warning,
body: context.l10n.confirmUpdatingkey,
firstButtonLabel: context.l10n.yes,
secondButtonAction: ButtonAction.cancel,
secondButtonLabel: context.l10n.cancel,
);
if (result == null) return;
if (result.action != ButtonAction.first) {
return;
}
}
final Code newCode = widget.code == null
? Code.fromAccountAndSecret(
account,
issuer,
secret,
)
: widget.code!.copyWith(
account: account,
issuer: issuer,
secret: secret,
);
// Verify the validity of the code
getOTP(newCode);
Navigator.of(context).pop(newCode);
} catch (e) {
_showIncorrectDetailsDialog(context);
}
}
void _showIncorrectDetailsDialog(
BuildContext context, {
String? message,

View File

@@ -89,7 +89,7 @@ class ViewQrPage extends StatelessWidget {
child: Text(l10n.back),
),
),
)
),
],
),
),

View File

@@ -1,5 +1,3 @@
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ui/tools/app_lock.dart';
import 'package:ente_auth/utils/auth_util.dart';
@@ -19,7 +17,7 @@ class LocalAuthenticationService {
) async {
if (await _isLocalAuthSupportedOnDevice()) {
AppLock.of(context)!.setEnabled(false);
final result = await requestAuthentication(infoMessage);
final result = await requestAuthentication(context, infoMessage);
AppLock.of(context)!.setEnabled(
Configuration.instance.shouldShowLockScreen(),
);
@@ -43,6 +41,7 @@ class LocalAuthenticationService {
if (await LocalAuthentication().isDeviceSupported()) {
AppLock.of(context)!.disable();
final result = await requestAuthentication(
context,
infoMessage,
);
if (result) {

View File

@@ -13,6 +13,7 @@ class PreferenceService {
static const kShouldShowLargeIconsKey = "should_show_large_icons";
static const kShouldHideCodesKey = "should_hide_codes";
static const kShouldAutoFocusOnSearchBar = "should_auto_focus_on_search_bar";
static const kShouldMinimizeOnCopy = "should_minimize_on_copy";
Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
@@ -64,4 +65,16 @@ class PreferenceService {
await _prefs.setBool(kShouldAutoFocusOnSearchBar, value);
Bus.instance.fire(IconsChangedEvent());
}
bool shouldMinimizeOnCopy() {
if (_prefs.containsKey(kShouldMinimizeOnCopy)) {
return _prefs.getBool(kShouldMinimizeOnCopy)!;
} else {
return false;
}
}
Future<void> setShouldMinimizeOnCopy(bool value) async {
await _prefs.setBool(kShouldMinimizeOnCopy, value);
}
}

View File

@@ -1,5 +1,3 @@
import 'dart:io';
import 'package:ente_auth/core/constants.dart';
@@ -94,7 +92,7 @@ class UpdateService {
// Note: in auth, currently we don't have a way to identify if the
// app was installed from play store, f-droid or github based on pkg name
if (Platform.isAndroid) {
if(flavor == "playstore") {
if (flavor == "playstore") {
return const Tuple2(
"Play Store",
"market://details??id=io.ente.auth",
@@ -120,8 +118,7 @@ class UpdateService {
// Fall back if we fail to open play-store market app on android
if (Platform.isAndroid && url.startsWith("market://")) {
launchUrlString(
"https://play.google.com/store/apps/details?id=io"
".ente.auth",
"https://play.google.com/store/apps/details?id=io.ente.auth",
mode: LaunchMode.externalApplication,
).ignore();
}
@@ -129,7 +126,8 @@ class UpdateService {
}
bool isIndependent() {
return flavor == "independent" || _packageInfo.packageName.endsWith("independent");
return flavor == "independent" ||
_packageInfo.packageName.endsWith("independent");
}
}

View File

@@ -24,13 +24,12 @@ import 'package:ente_auth/ui/account/ott_verification_page.dart';
import 'package:ente_auth/ui/account/password_entry_page.dart';
import 'package:ente_auth/ui/account/password_reentry_page.dart';
import 'package:ente_auth/ui/account/recovery_page.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
import 'package:ente_auth/ui/common/progress_dialog.dart';
import 'package:ente_auth/ui/home_page.dart';
import 'package:ente_auth/ui/two_factor_authentication_page.dart';
import 'package:ente_auth/ui/two_factor_recovery_page.dart';
import 'package:ente_auth/utils/crypto_util.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/email_util.dart';
import 'package:ente_auth/utils/toast_util.dart';
import "package:flutter/foundation.dart";
import 'package:flutter/material.dart';
@@ -46,9 +45,10 @@ import "package:uuid/uuid.dart";
class UserService {
static const keyHasEnabledTwoFactor = "has_enabled_two_factor";
static const keyUserDetails = "user_details";
static const kReferralSource = "referral_source";
static const kCanDisableEmailMFA = "can_disable_email_mfa";
static const kIsEmailMFAEnabled = "is_email_mfa_enabled";
final SRP6GroupParameters kDefaultSrpGroup = SRP6StandardGroups.rfc5054_4096;
final SRP6GroupParameters kDefaultSrpGroup = SRP6StandardGroups.rfc5054_4096;
final _dio = Network.instance.getDio();
final _enteDio = Network.instance.enteDio;
final _logger = Logger((UserService).toString());
@@ -68,12 +68,12 @@ class UserService {
}
Future<void> sendOtt(
BuildContext context,
String email, {
bool isChangeEmail = false,
bool isCreateAccountScreen = false,
bool isResetPasswordScreen = false,
}) async {
BuildContext context,
String email, {
bool isChangeEmail = false,
bool isCreateAccountScreen = false,
bool isResetPasswordScreen = false,
}) async {
final dialog = createProgressDialog(context, context.l10n.pleaseWait);
await dialog.show();
try {
@@ -122,17 +122,16 @@ class UserService {
}
Future<void> sendFeedback(
BuildContext context,
String feedback, {
String type = "SubCancellation",
}) async {
BuildContext context,
String feedback, {
String type = "SubCancellation",
}) async {
await _dio.post(
_config.getHttpEndpoint() + "/anonymous/feedback",
data: {"feedback": feedback, "type": "type"},
);
}
Future<UserDetails> getUserDetailsV2({
bool memoryCount = false,
bool shouldCache = true,
@@ -146,9 +145,15 @@ class UserService {
);
final userDetails = UserDetails.fromMap(response.data);
if (shouldCache) {
if(userDetails.profileData != null) {
_preferences.setBool(kIsEmailMFAEnabled, userDetails.profileData!.isEmailMFAEnabled);
_preferences.setBool(kCanDisableEmailMFA, userDetails.profileData!.canDisableEmailMFA);
if (userDetails.profileData != null) {
_preferences.setBool(
kIsEmailMFAEnabled,
userDetails.profileData!.isEmailMFAEnabled,
);
_preferences.setBool(
kCanDisableEmailMFA,
userDetails.profileData!.canDisableEmailMFA,
);
}
// handle email change from different client
if (userDetails.email != _config.getEmail()) {
@@ -156,7 +161,7 @@ class UserService {
}
}
return userDetails;
} catch(e) {
} catch (e) {
_logger.warning("Failed to fetch", e);
rethrow;
}
@@ -210,15 +215,15 @@ class UserService {
//to close and only then to show the error dialog.
Future.delayed(
const Duration(milliseconds: 150),
() => showGenericErrorDialog(context: context),
() => showGenericErrorDialog(context: context),
);
rethrow;
}
}
Future<DeleteChallengeResponse?> getDeleteChallenge(
BuildContext context,
) async {
BuildContext context,
) async {
try {
final response = await _enteDio.get("/users/delete-challenge");
if (response.statusCode == 200) {
@@ -237,8 +242,9 @@ class UserService {
}
Future<void> deleteAccount(
BuildContext context,
String challengeResponse,) async {
BuildContext context,
String challengeResponse,
) async {
try {
final response = await _enteDio.delete(
"/users/delete",
@@ -258,18 +264,24 @@ class UserService {
}
}
Future<void> verifyEmail(BuildContext context, String ott, {bool
isResettingPasswordScreen = false,})
async {
Future<void> verifyEmail(
BuildContext context,
String ott, {
bool isResettingPasswordScreen = false,
}) async {
final dialog = createProgressDialog(context, context.l10n.pleaseWait);
await dialog.show();
final verifyData = {
"email": _config.getEmail(),
"ott": ott,
};
if (!_config.isLoggedIn()) {
verifyData["source"] = 'auth:' + _getRefSource();
}
try {
final response = await _dio.post(
_config.getHttpEndpoint() + "/users/verify-email",
data: {
"email": _config.getEmail(),
"ott": ott,
},
data: verifyData,
);
await dialog.hide();
if (response.statusCode == 200) {
@@ -280,14 +292,15 @@ class UserService {
} else {
await _saveConfiguration(response);
if (Configuration.instance.getEncryptedToken() != null) {
if(isResettingPasswordScreen) {
if (isResettingPasswordScreen) {
page = const RecoveryPage();
} else {
page = const PasswordReentryPage();
}
} else {
page = const PasswordEntryPage(mode: PasswordEntryMode.set,);
page = const PasswordEntryPage(
mode: PasswordEntryMode.set,
);
}
}
Navigator.of(context).pushAndRemoveUntil(
@@ -296,7 +309,7 @@ class UserService {
return page;
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
} else {
// should never reach here
@@ -336,10 +349,10 @@ class UserService {
}
Future<void> changeEmail(
BuildContext context,
String email,
String ott,
) async {
BuildContext context,
String email,
String ott,
) async {
final dialog = createProgressDialog(context, context.l10n.pleaseWait);
await dialog.show();
try {
@@ -431,9 +444,10 @@ class UserService {
}
Future<void> registerOrUpdateSrp(
Uint8List loginKey, {
SetKeysRequest? setKeysRequest,
}) async {
Uint8List loginKey, {
SetKeysRequest? setKeysRequest,
bool logOutOtherDevices = false,
}) async {
try {
final String username = const Uuid().v4().toString();
final SecureRandom random = _getSecureRandom();
@@ -466,14 +480,14 @@ class UserService {
);
if (response.statusCode == 200) {
final SetupSRPResponse setupSRPResponse =
SetupSRPResponse.fromJson(response.data);
SetupSRPResponse.fromJson(response.data);
final serverB =
SRP6Util.decodeBigInt(base64Decode(setupSRPResponse.srpB));
SRP6Util.decodeBigInt(base64Decode(setupSRPResponse.srpB));
// ignore: need to calculate secret to get M1, unused_local_variable
final clientS = client.calculateSecret(serverB);
final clientM = client.calculateClientEvidenceMessage();
late Response srpCompleteResponse;
if(setKeysRequest == null) {
if (setKeysRequest == null) {
srpCompleteResponse = await _enteDio.post(
"/users/srp/complete",
data: {
@@ -488,14 +502,15 @@ class UserService {
'setupID': setupSRPResponse.setupID,
'srpM1': base64Encode(SRP6Util.encodeBigInt(clientM!)),
'updatedKeyAttr': setKeysRequest.toMap(),
'logOutOtherDevices': logOutOtherDevices,
},
);
}
} else {
throw Exception("register-srp action failed");
}
} catch (e,s) {
_logger.severe("failed to register srp" ,e,s);
} catch (e, s) {
_logger.severe("failed to register srp", e, s);
rethrow;
}
}
@@ -512,133 +527,97 @@ class UserService {
}
Future<void> verifyEmailViaPassword(
BuildContext context,
SrpAttributes srpAttributes,
String userPassword,
) async {
final dialog = createProgressDialog(
context,
context.l10n.pleaseWait,
isDismissible: true,
);
await dialog.show();
BuildContext context,
SrpAttributes srpAttributes,
String userPassword,
ProgressDialog dialog,
) async {
late Uint8List keyEncryptionKey;
try {
keyEncryptionKey = await CryptoUtil.deriveKey(
utf8.encode(userPassword) as Uint8List,
CryptoUtil.base642bin(srpAttributes.kekSalt),
srpAttributes.memLimit,
srpAttributes.opsLimit,
);
final loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey);
final Uint8List identity = Uint8List.fromList(
utf8.encode(srpAttributes.srpUserID),
);
final Uint8List salt = base64Decode(srpAttributes.srpSalt);
final Uint8List password = loginKey;
final SecureRandom random = _getSecureRandom();
_logger.finest('Start deriving key');
keyEncryptionKey = await CryptoUtil.deriveKey(
utf8.encode(userPassword) as Uint8List,
CryptoUtil.base642bin(srpAttributes.kekSalt),
srpAttributes.memLimit,
srpAttributes.opsLimit,
);
_logger.finest('keyDerivation done, derive LoginKey');
final loginKey = await CryptoUtil.deriveLoginKey(keyEncryptionKey);
final Uint8List identity = Uint8List.fromList(
utf8.encode(srpAttributes.srpUserID),
);
_logger.finest('longinKey derivation done');
final Uint8List salt = base64Decode(srpAttributes.srpSalt);
final Uint8List password = loginKey;
final SecureRandom random = _getSecureRandom();
final client = SRP6Client(
group: kDefaultSrpGroup,
digest: Digest('SHA-256'),
random: random,
);
final client = SRP6Client(
group: kDefaultSrpGroup,
digest: Digest('SHA-256'),
random: random,
);
final A = client.generateClientCredentials(salt, identity, password);
final createSessionResponse = await _dio.post(
_config.getHttpEndpoint() + "/users/srp/create-session",
data: {
"srpUserID": srpAttributes.srpUserID,
"srpA": base64Encode(SRP6Util.encodeBigInt(A!)),
},
);
final String sessionID = createSessionResponse.data["sessionID"];
final String srpB = createSessionResponse.data["srpB"];
final A = client.generateClientCredentials(salt, identity, password);
final createSessionResponse = await _dio.post(
_config.getHttpEndpoint() + "/users/srp/create-session",
data: {
"srpUserID": srpAttributes.srpUserID,
"srpA": base64Encode(SRP6Util.encodeBigInt(A!)),
},
);
final String sessionID = createSessionResponse.data["sessionID"];
final String srpB = createSessionResponse.data["srpB"];
final serverB = SRP6Util.decodeBigInt(base64Decode(srpB));
// ignore: need to calculate secret to get M1, unused_local_variable
final clientS = client.calculateSecret(serverB);
final clientM = client.calculateClientEvidenceMessage();
final response = await _dio.post(
_config.getHttpEndpoint() + "/users/srp/verify-session",
data: {
"sessionID": sessionID,
"srpUserID": srpAttributes.srpUserID,
"srpM1": base64Encode(SRP6Util.encodeBigInt(clientM!)),
},
);
if (response.statusCode == 200) {
Widget page;
final String twoFASessionID = response.data["twoFactorSessionID"];
Configuration.instance.setVolatilePassword(userPassword);
if (twoFASessionID.isNotEmpty) {
page = TwoFactorAuthenticationPage(twoFASessionID);
} else {
await _saveConfiguration(response);
if (Configuration.instance.getEncryptedToken() != null) {
await Configuration.instance.decryptSecretsAndGetKeyEncKey(
userPassword,
Configuration.instance.getKeyAttributes()!,
keyEncryptionKey: keyEncryptionKey,
);
page = const HomePage();
} else {
throw Exception("unexpected response during email verification");
}
}
await dialog.hide();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) {
return page;
},
),
(route) => route.isFirst,
);
final serverB = SRP6Util.decodeBigInt(base64Decode(srpB));
// ignore: need to calculate secret to get M1, unused_local_variable
final clientS = client.calculateSecret(serverB);
final clientM = client.calculateClientEvidenceMessage();
final response = await _dio.post(
_config.getHttpEndpoint() + "/users/srp/verify-session",
data: {
"sessionID": sessionID,
"srpUserID": srpAttributes.srpUserID,
"srpM1": base64Encode(SRP6Util.encodeBigInt(clientM!)),
},
);
if (response.statusCode == 200) {
Widget page;
final String twoFASessionID = response.data["twoFactorSessionID"];
Configuration.instance.setVolatilePassword(userPassword);
if (twoFASessionID.isNotEmpty) {
page = TwoFactorAuthenticationPage(twoFASessionID);
} else {
// should never reach here
throw Exception("unexpected response during email verification");
}
} on DioError catch (e, s) {
await dialog.hide();
if (e.response != null && e.response!.statusCode == 401) {
final dialogChoice = await showChoiceDialog(
context,
title: context.l10n.incorrectPasswordTitle,
body: context.l10n.pleaseTryAgain,
firstButtonLabel: context.l10n.contactSupport,
secondButtonLabel: context.l10n.ok,
);
if (dialogChoice!.action == ButtonAction.first) {
await sendLogs(
context,
context.l10n.contactSupport,
"support@ente.io",
postShare: () {},
await _saveConfiguration(response);
if (Configuration.instance.getEncryptedToken() != null) {
await Configuration.instance.decryptSecretsAndGetKeyEncKey(
userPassword,
Configuration.instance.getKeyAttributes()!,
keyEncryptionKey: keyEncryptionKey,
);
page = const HomePage();
} else {
throw Exception("unexpected response during email verification");
}
} else {
_logger.fine('failed to verify password', e, s);
await showErrorDialog(
context,
context.l10n.oops,
context.l10n.verificationFailedPleaseTryAgain,
);
}
} catch (e, s) {
_logger.fine('failed to verify password', e, s);
await dialog.hide();
await showErrorDialog(
context,
context.l10n.oops,
context.l10n.verificationFailedPleaseTryAgain,
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) {
return page;
},
),
(route) => route.isFirst,
);
} else {
// should never reach here
throw Exception("unexpected response during email verification");
}
}
Future<void> updateKeyAttributes(KeyAttributes keyAttributes, Uint8List
loginKey,)
async {
Future<void> updateKeyAttributes(
KeyAttributes keyAttributes,
Uint8List loginKey, {
required bool logoutOtherDevices,
}) async {
try {
final setKeyRequest = SetKeysRequest(
kekSalt: keyAttributes.kekSalt,
@@ -647,11 +626,11 @@ class UserService {
memLimit: keyAttributes.memLimit,
opsLimit: keyAttributes.opsLimit,
);
await registerOrUpdateSrp(loginKey, setKeysRequest: setKeyRequest);
// await _enteDio.put(
// "/users/keys",
// data: setKeyRequest.toMap(),
// );
await registerOrUpdateSrp(
loginKey,
setKeysRequest: setKeyRequest,
logOutOtherDevices: logoutOtherDevices,
);
await _config.setKeyAttributes(keyAttributes);
} catch (e) {
_logger.severe(e);
@@ -679,10 +658,10 @@ class UserService {
}
Future<void> verifyTwoFactor(
BuildContext context,
String sessionID,
String code,
) async {
BuildContext context,
String sessionID,
String code,
) async {
final dialog = createProgressDialog(context, context.l10n.pleaseWait);
await dialog.show();
try {
@@ -703,7 +682,7 @@ class UserService {
return const PasswordReentryPage();
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
}
} on DioError catch (e) {
@@ -717,7 +696,7 @@ class UserService {
return const LoginPage();
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
} else {
showErrorDialog(
@@ -758,7 +737,7 @@ class UserService {
);
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
}
} on DioError catch (e) {
@@ -771,7 +750,7 @@ class UserService {
return const LoginPage();
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
} else {
showErrorDialog(
@@ -793,12 +772,12 @@ class UserService {
}
Future<void> removeTwoFactor(
BuildContext context,
String sessionID,
String recoveryKey,
String encryptedSecret,
String secretDecryptionNonce,
) async {
BuildContext context,
String sessionID,
String recoveryKey,
String encryptedSecret,
String secretDecryptionNonce,
) async {
final dialog = createProgressDialog(context, context.l10n.pleaseWait);
await dialog.show();
String secret;
@@ -847,7 +826,7 @@ class UserService {
return const PasswordReentryPage();
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
}
} on DioError catch (e) {
@@ -860,7 +839,7 @@ class UserService {
return const LoginPage();
},
),
(route) => route.isFirst,
(route) => route.isFirst,
);
} else {
showErrorDialog(
@@ -881,13 +860,6 @@ class UserService {
}
}
Future<void> _saveConfiguration(Response response) async {
await Configuration.instance.setUserID(response.data["id"]);
if (response.data["encryptedToken"] != null) {
@@ -904,6 +876,7 @@ class UserService {
bool? canDisableEmailMFA() {
return _preferences.getBool(kCanDisableEmailMFA);
}
bool hasEmailMFAEnabled() {
return _preferences.getBool(kIsEmailMFAEnabled) ?? true;
}
@@ -918,9 +891,16 @@ class UserService {
);
_preferences.setBool(kIsEmailMFAEnabled, isEnabled);
} catch (e) {
_logger.severe("Failed to update email mfa",e);
_logger.severe("Failed to update email mfa", e);
rethrow;
}
}
}
Future<void> setRefSource(String refSource) async {
await _preferences.setString(kReferralSource, refSource);
}
String _getRefSource() {
return _preferences.getString(kReferralSource) ?? "";
}
}

View File

@@ -47,7 +47,7 @@ class EnteColorScheme {
final Color warning800;
final Color caution500;
final List<Color> avatarColors;
const EnteColorScheme(
this.backgroundBase,
this.backgroundElevated,
@@ -69,7 +69,8 @@ class EnteColorScheme {
this.strokeFainter,
this.blurStrokeBase,
this.blurStrokeFaint,
this.blurStrokePressed, {
this.blurStrokePressed,
this.avatarColors, {
this.primaryGreen = _primaryGreen,
this.primary700 = _primary700,
this.primary500 = _primary500,
@@ -105,6 +106,7 @@ const EnteColorScheme lightScheme = EnteColorScheme(
blurStrokeBaseLight,
blurStrokeFaintLight,
blurStrokePressedLight,
avatarLight,
);
const EnteColorScheme darkScheme = EnteColorScheme(
@@ -129,6 +131,7 @@ const EnteColorScheme darkScheme = EnteColorScheme(
blurStrokeBaseDark,
blurStrokeFaintDark,
blurStrokePressedDark,
avatarDark,
);
// Background Colors
@@ -204,3 +207,55 @@ const Color warning500 = Color.fromRGBO(255, 101, 101, 1);
const Color _warning400 = Color.fromRGBO(255, 111, 111, 1);
const Color _caution500 = Color.fromRGBO(255, 194, 71, 1);
const List<Color> avatarLight = [
Color.fromRGBO(118, 84, 154, 1),
Color.fromRGBO(223, 120, 97, 1),
Color.fromRGBO(148, 180, 159, 1),
Color.fromRGBO(135, 162, 251, 1),
Color.fromRGBO(198, 137, 198, 1),
Color.fromRGBO(198, 137, 198, 1),
Color.fromRGBO(50, 82, 136, 1),
Color.fromRGBO(133, 180, 224, 1),
Color.fromRGBO(193, 163, 163, 1),
Color.fromRGBO(193, 163, 163, 1),
Color.fromRGBO(66, 97, 101, 1),
Color.fromRGBO(66, 97, 101, 1),
Color.fromRGBO(66, 97, 101, 1),
Color.fromRGBO(221, 157, 226, 1),
Color.fromRGBO(130, 171, 139, 1),
Color.fromRGBO(155, 187, 232, 1),
Color.fromRGBO(143, 190, 190, 1),
Color.fromRGBO(138, 195, 161, 1),
Color.fromRGBO(168, 176, 242, 1),
Color.fromRGBO(176, 198, 149, 1),
Color.fromRGBO(233, 154, 173, 1),
Color.fromRGBO(209, 132, 132, 1),
Color.fromRGBO(120, 181, 167, 1),
];
const List<Color> avatarDark = [
Color.fromRGBO(118, 84, 154, 1),
Color.fromRGBO(223, 120, 97, 1),
Color.fromRGBO(148, 180, 159, 1),
Color.fromRGBO(135, 162, 251, 1),
Color.fromRGBO(198, 137, 198, 1),
Color.fromRGBO(147, 125, 194, 1),
Color.fromRGBO(50, 82, 136, 1),
Color.fromRGBO(133, 180, 224, 1),
Color.fromRGBO(193, 163, 163, 1),
Color.fromRGBO(225, 160, 89, 1),
Color.fromRGBO(66, 97, 101, 1),
Color.fromRGBO(107, 119, 178, 1),
Color.fromRGBO(149, 127, 239, 1),
Color.fromRGBO(221, 157, 226, 1),
Color.fromRGBO(130, 171, 139, 1),
Color.fromRGBO(155, 187, 232, 1),
Color.fromRGBO(143, 190, 190, 1),
Color.fromRGBO(138, 195, 161, 1),
Color.fromRGBO(168, 176, 242, 1),
Color.fromRGBO(176, 198, 149, 1),
Color.fromRGBO(233, 154, 173, 1),
Color.fromRGBO(209, 132, 132, 1),
Color.fromRGBO(120, 181, 167, 1),
];

View File

@@ -3,8 +3,10 @@ import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/ente_theme_data.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:ente_auth/ui/common/dynamic_fab.dart';
import 'package:ente_auth/ui/common/web_page.dart';
import 'package:ente_auth/utils/toast_util.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:password_strength/password_strength.dart';
@@ -30,6 +32,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
String? _email;
String? _password;
String _cnfPassword = '';
String _referralSource = '';
double _passwordStrength = 0.0;
bool _emailIsValid = false;
bool _hasAgreedToTOS = true;
@@ -104,6 +107,7 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
onPressedFunction: () {
_config.setVolatilePassword(_passwordController1.text);
UserService.instance.setEmail(_email!);
UserService.instance.setRefSource(_referralSource);
UserService.instance
.sendOtt(context, _email!, isCreateAccountScreen: true);
FocusScope.of(context).unfocus();
@@ -325,6 +329,51 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
),
),
const SizedBox(height: 4),
Padding(
padding:
const EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: Text(
context.l10n.hearUsWhereTitle,
style: getEnteTextTheme(context).smallFaint,
),
),
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: TextFormField(
style: Theme.of(context).textTheme.titleMedium,
decoration: InputDecoration(
fillColor: null,
filled: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 14,
),
border: UnderlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(6),
),
suffixIcon: InkWell(
onTap: () {
showToast(
context,
context.l10n.hearUsExplanation,
);
},
child: Icon(
Icons.info_outline_rounded,
color: getEnteColorScheme(context).strokeMuted,
),
),
),
onChanged: (value) {
_referralSource = value.trim();
},
autocorrect: false,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
),
),
const Divider(thickness: 1),
const SizedBox(height: 12),
_getAgreement(),
@@ -371,39 +420,43 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Expanded(
child: StyledText(
text: context.l10n.signUpTerms,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 12),
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(fontSize: 12),
tags: {
'u-terms': StyledTextActionTag(
(String? text, Map<String?, String?> attrs) => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return WebPage(
context.l10n.termsOfServicesTitle,
"https://ente.io/terms",
);
},
),
(String? text, Map<String?, String?> attrs) =>
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return WebPage(
context.l10n.termsOfServicesTitle,
"https://ente.io/terms",
);
},
),
),
style: const TextStyle(
decoration: TextDecoration.underline,
),
),
'u-policy': StyledTextActionTag(
(String? text, Map<String?, String?> attrs) => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return WebPage(
context.l10n.privacyPolicyTitle,
"https://ente.io/privacy",
);
},
),
(String? text, Map<String?, String?> attrs) =>
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return WebPage(
context.l10n.privacyPolicyTitle,
"https://ente.io/privacy",
);
},
),
),
style: const TextStyle(
decoration: TextDecoration.underline,
),
)
),
},
),
),
@@ -434,20 +487,23 @@ class _EmailEntryPageState extends State<EmailEntryPage> {
Expanded(
child: StyledText(
text: context.l10n.ackPasswordLostWarning,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 12),
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(fontSize: 12),
tags: {
'underline': StyledTextActionTag(
(String? text, Map<String?, String?> attrs) => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return WebPage(
context.l10n.encryption,
"https://ente.io/architecture",
);
},
),
(String? text, Map<String?, String?> attrs) =>
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return WebPage(
context.l10n.encryption,
"https://ente.io/architecture",
);
},
),
),
style: const TextStyle(
decoration: TextDecoration.underline,
),

View File

@@ -204,14 +204,14 @@ class _LoginPageState extends State<LoginPage> {
style: const TextStyle(
decoration: TextDecoration.underline,
),
)
),
},
),
),
Expanded(
flex: 2,
child: Container(),
)
),
],
),
),

View File

@@ -1,11 +1,14 @@
import "package:dio/dio.dart";
import 'package:ente_auth/core/configuration.dart';
import "package:ente_auth/core/errors.dart";
import "package:ente_auth/l10n/l10n.dart";
import "package:ente_auth/models/api/user/srp.dart";
import "package:ente_auth/services/user_service.dart";
import "package:ente_auth/theme/ente_theme.dart";
import 'package:ente_auth/ui/common/dynamic_fab.dart';
import "package:ente_auth/ui/components/buttons/button_widget.dart";
import "package:ente_auth/utils/dialog_util.dart";
import "package:ente_auth/utils/email_util.dart";
import 'package:flutter/material.dart';
import "package:logging/logging.dart";
@@ -16,14 +19,16 @@ import "package:logging/logging.dart";
// volatile password.
class LoginPasswordVerificationPage extends StatefulWidget {
final SrpAttributes srpAttributes;
const LoginPasswordVerificationPage({Key? key, required this.srpAttributes}) : super(key: key);
const LoginPasswordVerificationPage({Key? key, required this.srpAttributes})
: super(key: key);
@override
State<LoginPasswordVerificationPage> createState() => _LoginPasswordVerificationPageState();
State<LoginPasswordVerificationPage> createState() =>
_LoginPasswordVerificationPageState();
}
class _LoginPasswordVerificationPageState extends
State<LoginPasswordVerificationPage> {
class _LoginPasswordVerificationPageState
extends State<LoginPasswordVerificationPage> {
final _logger = Logger((_LoginPasswordVerificationPageState).toString());
final _passwordController = TextEditingController();
final FocusNode _passwordFocusNode = FocusNode();
@@ -74,9 +79,7 @@ State<LoginPasswordVerificationPage> {
buttonText: context.l10n.logInLabel,
onPressedFunction: () async {
FocusScope.of(context).unfocus();
await UserService.instance.verifyEmailViaPassword(context, widget
.srpAttributes,
_passwordController.text,);
await verifyPassword(context, _passwordController.text);
},
),
floatingActionButtonLocation: fabLocation(),
@@ -84,6 +87,106 @@ State<LoginPasswordVerificationPage> {
);
}
Future<void> verifyPassword(BuildContext context, String password) async {
final dialog = createProgressDialog(
context,
context.l10n.pleaseWait,
isDismissible: true,
);
await dialog.show();
try {
await UserService.instance.verifyEmailViaPassword(
context,
widget.srpAttributes,
password,
dialog,
);
} on DioError catch (e, s) {
await dialog.hide();
if (e.response != null && e.response!.statusCode == 401) {
_logger.severe('server reject, failed verify SRP login', e, s);
await _showContactSupportDialog(
context,
context.l10n.incorrectPasswordTitle,
context.l10n.pleaseTryAgain,
);
} else {
_logger.severe('API failure during SRP login', e, s);
if (e.type == DioErrorType.other) {
await _showContactSupportDialog(
context,
context.l10n.noInternetConnection,
context.l10n.pleaseCheckYourInternetConnectionAndTryAgain,
);
} else {
await _showContactSupportDialog(
context,
context.l10n.oops,
context.l10n.verificationFailedPleaseTryAgain,
);
}
}
} catch (e, s) {
_logger.info('error during loginViaPassword', e);
await dialog.hide();
if (e is LoginKeyDerivationError) {
_logger.severe('loginKey derivation error', e, s);
// LoginKey err, perform regular login via ott verification
await UserService.instance.sendOtt(
context,
email!,
isCreateAccountScreen: true,
);
return;
} else if (e is KeyDerivationError) {
// device is not powerful enough to perform derive key
final dialogChoice = await showChoiceDialog(
context,
title: context.l10n.recreatePasswordTitle,
body: context.l10n.recreatePasswordBody,
firstButtonLabel: context.l10n.useRecoveryKey,
);
if (dialogChoice!.action == ButtonAction.first) {
await UserService.instance.sendOtt(
context,
email!,
isResetPasswordScreen: true,
);
}
return;
} else {
_logger.severe('unexpected error while verifying password', e, s);
await _showContactSupportDialog(
context,
context.l10n.oops,
context.l10n.verificationFailedPleaseTryAgain,
);
}
}
}
Future<void> _showContactSupportDialog(
BuildContext context,
String title,
String message,
) async {
final dialogChoice = await showChoiceDialog(
context,
title: title,
body: message,
firstButtonLabel: context.l10n.contactSupport,
secondButtonLabel: context.l10n.ok,
);
if (dialogChoice!.action == ButtonAction.first) {
await sendLogs(
context,
context.l10n.contactSupport,
"auth@ente.io",
postShare: () {},
);
}
}
Widget _getBody() {
return Column(
children: [
@@ -92,17 +195,22 @@ State<LoginPasswordVerificationPage> {
child: ListView(
children: [
Padding(
padding:
const EdgeInsets.only(top: 30, left: 20, right: 20),
padding: const EdgeInsets.only(top: 30, left: 20, right: 20),
child: Text(
context.l10n.enterPassword,
style: Theme.of(context).textTheme.headlineMedium,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 30, left: 22, right:
20,),
child: Text(email ?? '', style: getEnteTextTheme(context).smallMuted,),
padding: const EdgeInsets.only(
bottom: 30,
left: 22,
right: 20,
),
child: Text(
email ?? '',
style: getEnteTextTheme(context).smallMuted,
),
),
Visibility(
// hidden textForm for suggesting auto-fill service for saving
@@ -133,19 +241,19 @@ State<LoginPasswordVerificationPage> {
),
suffixIcon: _passwordInFocus
? IconButton(
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Theme.of(context).iconTheme.color,
size: 20,
),
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
)
icon: Icon(
_passwordVisible
? Icons.visibility
: Icons.visibility_off,
color: Theme.of(context).iconTheme.color,
size: 20,
),
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
)
: null,
),
style: const TextStyle(
@@ -176,9 +284,11 @@ State<LoginPasswordVerificationPage> {
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
await UserService.instance
.sendOtt(context, email!,
isResetPasswordScreen: true,);
await UserService.instance.sendOtt(
context,
email!,
isResetPasswordScreen: true,
);
},
child: Center(
child: Text(
@@ -187,9 +297,9 @@ State<LoginPasswordVerificationPage> {
.textTheme
.titleMedium!
.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
),
@@ -213,15 +323,15 @@ State<LoginPasswordVerificationPage> {
.textTheme
.titleMedium!
.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
),
],
),
)
),
],
),
),
@@ -229,4 +339,4 @@ State<LoginPasswordVerificationPage> {
],
);
}
}
}

View File

@@ -152,7 +152,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
SizedBox(
width: MediaQuery.of(context).size.width * 0.2,
height: 1,
)
),
],
),
),
@@ -203,7 +203,7 @@ class _OTTVerificationPageState extends State<OTTVerificationPage> {
decoration: TextDecoration.underline,
),
),
)
),
],
),
),

View File

@@ -5,6 +5,7 @@ import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/ui/account/recovery_key_page.dart';
import 'package:ente_auth/ui/common/dynamic_fab.dart';
import 'package:ente_auth/ui/common/web_page.dart';
import 'package:ente_auth/ui/components/models/button_type.dart';
import 'package:ente_auth/ui/home_page.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/navigation_util.dart';
@@ -24,8 +25,7 @@ enum PasswordEntryMode {
class PasswordEntryPage extends StatefulWidget {
final PasswordEntryMode mode;
const PasswordEntryPage({required this.mode, Key? key})
: super(key: key);
const PasswordEntryPage({required this.mode, Key? key}) : super(key: key);
@override
State<PasswordEntryPage> createState() => _PasswordEntryPageState();
@@ -180,10 +180,11 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
.copyWith(fontSize: 14),
tags: {
'underline': StyledTextTag(
style: Theme.of(context).textTheme.titleMedium!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
style:
Theme.of(context).textTheme.titleMedium!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
},
),
@@ -356,10 +357,11 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
child: RichText(
text: TextSpan(
text: context.l10n.howItWorks,
style: Theme.of(context).textTheme.titleMedium!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
style:
Theme.of(context).textTheme.titleMedium!.copyWith(
fontSize: 14,
decoration: TextDecoration.underline,
),
),
),
),
@@ -374,13 +376,18 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
}
void _updatePassword() async {
final logOutFromOthers = await logOutFromOtherDevices(context);
final dialog =
createProgressDialog(context, context.l10n.generatingEncryptionKeys);
await dialog.show();
try {
final result = await Configuration.instance
.getAttributesForNewPassword(_passwordController1.text);
await UserService.instance.updateKeyAttributes(result.item1, result.item2);
await UserService.instance.updateKeyAttributes(
result.item1,
result.item2,
logoutOtherDevices: logOutFromOthers,
);
await dialog.hide();
showShortToast(context, context.l10n.passwordChangedSuccessfully);
Navigator.of(context).pop();
@@ -394,13 +401,34 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
}
}
Future<bool> logOutFromOtherDevices(BuildContext context) async {
bool logOutFromOther = true;
await showChoiceDialog(
context,
title: context.l10n.signOutFromOtherDevices,
body: context.l10n.signOutOtherBody,
isDismissible: false,
firstButtonLabel: context.l10n.signOutOtherDevices,
firstButtonType: ButtonType.critical,
firstButtonOnTap: () async {
logOutFromOther = true;
},
secondButtonLabel: context.l10n.doNotSignOut,
secondButtonOnTap: () async {
logOutFromOther = false;
},
);
return logOutFromOther;
}
Future<void> _showRecoveryCodeDialog(String password) async {
final l10n = context.l10n;
final dialog =
createProgressDialog(context, l10n.generatingEncryptionKeysTitle);
await dialog.show();
try {
final KeyGenResult result = await Configuration.instance.generateKey(password);
final KeyGenResult result =
await Configuration.instance.generateKey(password);
Configuration.instance.setVolatilePassword(null);
await dialog.hide();
onDone() async {

View File

@@ -310,7 +310,7 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
),
],
),
)
),
],
),
),

View File

@@ -191,7 +191,7 @@ class _RecoveryKeyPageState extends State<RecoveryKeyPage> {
children: _saveOptions(context, recoveryKey),
),
),
)
),
],
), // columnEnds
),

View File

@@ -196,7 +196,7 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
),
),
),
const SizedBox(height: 20)
const SizedBox(height: 20),
],
),
),

View File

@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:clipboard/clipboard.dart';
import 'package:ente_auth/core/configuration.dart';
@@ -7,6 +8,7 @@ import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart';
import 'package:ente_auth/onboarding/view/view_qr_page.dart';
import 'package:ente_auth/services/local_authentication_service.dart';
import 'package:ente_auth/services/preference_service.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/ui/code_timer_progress.dart';
@@ -17,6 +19,7 @@ import 'package:ente_auth/utils/totp_util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:logging/logging.dart';
import 'package:move_to_background/move_to_background.dart';
class CodeWidget extends StatefulWidget {
final Code code;
@@ -141,7 +144,7 @@ class _CodeWidgetState extends State<CodeWidget> {
borderRadius: BorderRadius.circular(10),
),
onTap: () {
_copyToClipboard();
_copyCurrentOTPToClipboard();
},
onDoubleTap: isMaskingEnabled
? () {
@@ -153,7 +156,7 @@ class _CodeWidgetState extends State<CodeWidget> {
}
: null,
onLongPress: () {
_copyToClipboard();
_copyCurrentOTPToClipboard();
},
child: _getCardContents(l10n),
),
@@ -322,23 +325,41 @@ class _CodeWidgetState extends State<CodeWidget> {
? const EdgeInsets.only(left: 16)
: const EdgeInsets.all(0),
child: IconUtils.instance.getIcon(
context,
safeDecode(widget.code.issuer).trim(),
width: _shouldShowLargeIcon ? 42 : 24,
),
);
}
void _copyToClipboard() {
FlutterClipboard.copy(_getCurrentOTP())
.then((value) => showToast(context, context.l10n.copiedToClipboard));
void _copyCurrentOTPToClipboard() async {
_copyToClipboard(
_getCurrentOTP(),
confirmationMessage: context.l10n.copiedToClipboard,
);
}
void _copyNextToClipboard() {
FlutterClipboard.copy(_getNextTotp()).then(
(value) => showToast(context, context.l10n.copiedNextToClipboard),
_copyToClipboard(
_getNextTotp(),
confirmationMessage: context.l10n.copiedNextToClipboard,
);
}
void _copyToClipboard(
String content, {
required String confirmationMessage,
}) async {
final shouldMinimizeOnCopy =
PreferenceService.instance.shouldMinimizeOnCopy();
await FlutterClipboard.copy(content);
showToast(context, confirmationMessage);
if (Platform.isAndroid && shouldMinimizeOnCopy) {
MoveToBackground.moveTaskToBack();
}
}
void _onNextHotpTapped() {
if (widget.code.type == Type.hotp) {
CodeStore.instance
@@ -351,6 +372,11 @@ class _CodeWidgetState extends State<CodeWidget> {
}
Future<void> _onEditPressed(_) async {
bool _isAuthSuccessful = await LocalAuthenticationService.instance
.requestLocalAuthentication(context, context.l10n.editCodeAuthMessage);
if (!_isAuthSuccessful) {
return;
}
final Code? code = await Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
@@ -364,6 +390,11 @@ class _CodeWidgetState extends State<CodeWidget> {
}
Future<void> _onShowQrPressed(_) async {
bool _isAuthSuccessful = await LocalAuthenticationService.instance
.requestLocalAuthentication(context, context.l10n.showQRAuthMessage);
if (!_isAuthSuccessful) {
return;
}
// ignore: unused_local_variable
final Code? code = await Navigator.of(context).push(
MaterialPageRoute(
@@ -375,6 +406,14 @@ class _CodeWidgetState extends State<CodeWidget> {
}
void _onDeletePressed(_) async {
bool _isAuthSuccessful =
await LocalAuthenticationService.instance.requestLocalAuthentication(
context,
context.l10n.deleteCodeAuthMessage,
);
if (!_isAuthSuccessful) {
return;
}
final l10n = context.l10n;
await showChoiceActionSheet(
context,

View File

@@ -30,7 +30,7 @@ class DynamicFAB extends StatelessWidget {
spreadRadius: 200,
blurRadius: 100,
offset: const Offset(0, 230),
)
),
],
),
width: double.infinity,

View File

@@ -277,7 +277,7 @@ class _BodyState extends State<_Body> {
_direction == TextDirection.ltr ? loader : text,
const SizedBox(width: 8.0),
_direction == TextDirection.rtl ? loader : text,
const SizedBox(width: 8.0)
const SizedBox(width: 8.0),
],
),
],

View File

@@ -308,7 +308,7 @@ class _ButtonChildWidgetState extends State<ButtonChildWidget> {
overflow: TextOverflow.ellipsis,
),
),
)
),
],
);
},

View File

@@ -48,7 +48,7 @@ class CaptionedTextWidget extends StatelessWidget {
],
),
),
)
),
],
),
),

View File

@@ -280,7 +280,7 @@ class _TextInputDialogState extends State<TextInputDialog> {
),
),
],
)
),
],
),
),

View File

@@ -61,7 +61,7 @@ class TitleBarWidget extends StatelessWidget {
: Text(
caption!,
style: textTheme.mini.copyWith(color: colorTheme.textMuted),
)
),
],
),
),
@@ -112,7 +112,7 @@ class TitleBarWidget extends StatelessWidget {
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
)
),
],
),
),

View File

@@ -56,7 +56,7 @@ class CoachMarkWidget extends StatelessWidget {
},
child: Text(l10n.ok),
),
)
),
],
),
],

View File

@@ -158,7 +158,7 @@ class _HomePageState extends State<HomePage> {
}
},
child: Scaffold(
drawerEnableOpenDragGesture: true,
drawerEnableOpenDragGesture: !Platform.isAndroid,
drawer: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 428),
child: Drawer(

View File

@@ -46,7 +46,8 @@ class ScannerGoogleAuthPageState extends State<ScannerGoogleAuthPage> {
child: QRView(
key: qrKey,
overlay: QrScannerOverlayShape(
borderColor: getEnteColorScheme(context).primary700,),
borderColor: getEnteColorScheme(context).primary700,
),
onQRViewCreated: _onQRViewCreated,
formatsAllowed: const [BarcodeFormat.qrcode],
),
@@ -56,7 +57,7 @@ class ScannerGoogleAuthPageState extends State<ScannerGoogleAuthPage> {
child: Center(
child: (totp != null) ? Text(totp!) : Text(l10n.scanACode),
),
)
),
],
),
);

View File

@@ -51,7 +51,7 @@ class ScannerPageState extends State<ScannerPage> {
child: Center(
child: (totp != null) ? Text(totp!) : Text(l10n.scanACode),
),
)
),
],
),
);

View File

@@ -0,0 +1,209 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/services/authenticator_service.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/ui/common/progress_dialog.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
import 'package:ente_auth/ui/components/dialog_widget.dart';
import 'package:ente_auth/ui/components/models/button_type.dart';
import 'package:ente_auth/ui/settings/data/import/import_success.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:pointycastle/export.dart';
Future<void> show2FasImportInstruction(BuildContext context) async {
final l10n = context.l10n;
final result = await showDialogWidget(
context: context,
title: l10n.importFromApp("2FAS Authenticator"),
body: l10n.import2FasGuide,
buttons: [
ButtonWidget(
buttonType: ButtonType.primary,
labelText: l10n.importSelectAppExport("2FAS Authenticator"),
isInAlert: true,
buttonSize: ButtonSize.large,
buttonAction: ButtonAction.first,
),
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: context.l10n.cancel,
buttonSize: ButtonSize.large,
isInAlert: true,
buttonAction: ButtonAction.second,
),
],
);
if (result?.action != null && result!.action != ButtonAction.cancel) {
if (result.action == ButtonAction.first) {
await _pick2FasFile(context);
} else {}
}
}
Future<void> _pick2FasFile(BuildContext context) async {
final l10n = context.l10n;
FilePickerResult? result = await FilePicker.platform
.pickFiles(dialogTitle: l10n.importSelectJsonFile);
if (result == null) {
return;
}
final ProgressDialog progressDialog =
createProgressDialog(context, l10n.pleaseWait);
await progressDialog.show();
try {
String path = result.files.single.path!;
int? count = await _process2FasExportFile(context, path, progressDialog);
await progressDialog.hide();
if (count != null) {
await importSuccessDialog(context, count);
}
} catch (e, s) {
Logger('2FASImport').severe('exception while processing import', e, s);
await progressDialog.hide();
await showErrorDialog(
context,
context.l10n.sorry,
context.l10n.importFailureDesc,
);
}
}
Future<int?> _process2FasExportFile(
BuildContext context,
String path,
final ProgressDialog dialog,
) async {
File file = File(path);
final jsonString = await file.readAsString();
final decodedJson = jsonDecode(jsonString);
int version = (decodedJson['schemaVersion'] ?? 0) as int;
if (version != 3 && version != 4) {
await dialog.hide();
// todo: extract strings for l10n. Use same naming format as in aegis
// to avoid duplicate translation efforts.
await showErrorDialog(
context,
'Unsupported format: $version',
version == 0
? "The selected file is not a valid 2FAS Authenticator export."
: "Sorry, the app doesn't support this version of 2FAS Authenticator export",
);
return null;
}
var decodedServices = decodedJson['services'];
// https://github.com/twofas/2fas-android/blob/e97f1a1040eafaed6d5284d54d33403dff215886/data/services/src/main/java/com/twofasapp/data/services/domain/BackupContent.kt#L39
final isEncrypted = decodedJson['reference'] != null;
if (isEncrypted) {
String? password;
try {
await showTextInputDialog(
context,
title: "Enter password to decrypt 2FAS backup",
submitButtonLabel: "Submit",
isPasswordInput: true,
onSubmit: (value) async {
password = value;
},
);
if (password == null) {
await dialog.hide();
return null;
}
final content = decrypt2FasVault(decodedJson, password: password!);
decodedServices = jsonDecode(content);
} catch (e, s) {
Logger("2FASImport").warning("exception while decrypting backup", e, s);
await dialog.hide();
if (password != null) {
await showErrorDialog(
context,
"Failed to decrypt 2Fas export",
"Please check your password and try again.",
);
}
return null;
}
}
final parsedCodes = [];
for (var item in decodedServices) {
var kind = item['otp']['tokenType'];
var account = item['otp']['account'] ?? '';
var issuer = item['otp']['issuer'] ?? item['name'] ?? '';
var algorithm = item['otp']['algorithm'];
var secret = item['secret'];
var timer = item['otp']['period'];
var digits = item['otp']['digits'];
var counter = item['otp']['counter'];
// Build the OTP URL
String otpUrl;
if (kind.toLowerCase() == 'totp') {
otpUrl =
'otpauth://$kind/$issuer:$account?secret=$secret&issuer=$issuer&algorithm=$algorithm&digits=$digits&period=$timer';
} else if (kind.toLowerCase() == 'hotp') {
otpUrl =
'otpauth://$kind/$issuer:$account?secret=$secret&issuer=$issuer&algorithm=$algorithm&digits=$digits&counter=$counter';
} else {
throw Exception('Invalid OTP type');
}
parsedCodes.add(Code.fromRawData(otpUrl));
}
for (final code in parsedCodes) {
await CodeStore.instance.addCode(code, shouldSync: false);
}
unawaited(AuthenticatorService.instance.onlineSync());
int count = parsedCodes.length;
return count;
}
String decrypt2FasVault(dynamic data, {required String password}) {
int ITERATION_COUNT = 10000;
int KEY_SIZE = 256;
final String encryptedServices = data["servicesEncrypted"];
var split = encryptedServices.split(":");
final encryptedData = base64.decode(split[0]);
final salt = base64.decode(split[1]);
final iv = base64.decode(split[2]);
// derive 256 key using PBKDF2WithHmacSHA256 and 10000 iterations and above salt
final pbkdf2 = PBKDF2KeyDerivator(HMac(SHA256Digest(), 64));
final params = Pbkdf2Parameters(
salt,
ITERATION_COUNT,
KEY_SIZE ~/ 8,
);
pbkdf2.init(params);
Uint8List key = Uint8List(KEY_SIZE ~/ 8);
pbkdf2.deriveKey(Uint8List.fromList(utf8.encode(password)), 0, key, 0);
final decrypted = decrypt(key, iv, encryptedData);
final utf8Decode = utf8.decode(decrypted);
return utf8Decode;
}
Uint8List decrypt(Uint8List key, Uint8List iv, Uint8List data) {
final cipher = GCMBlockCipher(AESEngine())
..init(
false,
AEADParameters(
KeyParameter(key),
128,
iv,
Uint8List.fromList(<int>[]),
),
);
final dbBytes = cipher.process(data);
return dbBytes;
}

View File

@@ -0,0 +1,103 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/services/authenticator_service.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
import 'package:ente_auth/ui/components/dialog_widget.dart';
import 'package:ente_auth/ui/components/models/button_type.dart';
import 'package:ente_auth/ui/settings/data/import/import_success.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Future<void> showBitwardenImportInstruction(BuildContext context) async {
final l10n = context.l10n;
final result = await showDialogWidget(
context: context,
title: l10n.importFromApp("Bitwarden"),
body: l10n.importBitwardenGuide,
buttons: [
ButtonWidget(
buttonType: ButtonType.primary,
labelText: l10n.importSelectJsonFile,
isInAlert: true,
buttonSize: ButtonSize.large,
buttonAction: ButtonAction.first,
),
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: context.l10n.cancel,
buttonSize: ButtonSize.large,
isInAlert: true,
buttonAction: ButtonAction.second,
),
],
);
if (result?.action != null && result!.action != ButtonAction.cancel) {
if (result.action == ButtonAction.first) {
await _pickBitwardenJsonFile(context);
}
}
}
Future<void> _pickBitwardenJsonFile(BuildContext context) async {
final l10n = context.l10n;
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result == null) {
return;
}
final progressDialog = createProgressDialog(context, l10n.pleaseWait);
await progressDialog.show();
try {
String path = result.files.single.path!;
int? count = await _processBitwardenExportFile(context, path);
await progressDialog.hide();
if (count != null) {
await importSuccessDialog(context, count);
}
} catch (e) {
await progressDialog.hide();
await showErrorDialog(
context,
context.l10n.sorry,
context.l10n.importFailureDesc,
);
}
}
Future<int?> _processBitwardenExportFile(
BuildContext context,
String path,
) async {
File file = File(path);
final jsonString = await file.readAsString();
final data = jsonDecode(jsonString);
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'];
parsedCodes.add(
Code.fromAccountAndSecret(
account,
issuer,
secret,
),
);
}
}
for (final code in parsedCodes) {
await CodeStore.instance.addCode(code, shouldSync: false);
}
unawaited(AuthenticatorService.instance.onlineSync());
return parsedCodes.length;
}

View File

@@ -1,4 +1,6 @@
import 'package:ente_auth/ui/settings/data/import/2fas_import.dart';
import 'package:ente_auth/ui/settings/data/import/aegis_import.dart';
import 'package:ente_auth/ui/settings/data/import/bitwarden_import.dart';
import 'package:ente_auth/ui/settings/data/import/encrypted_ente_import.dart';
import 'package:ente_auth/ui/settings/data/import/google_auth_import.dart';
import 'package:ente_auth/ui/settings/data/import/plain_text_import.dart';
@@ -31,6 +33,12 @@ class ImportService {
case ImportType.aegis:
showAegisImportInstruction(context);
break;
case ImportType.twoFas:
show2FasImportInstruction(context);
break;
case ImportType.bitwarden:
showBitwardenImportInstruction(context);
break;
}
}
}

View File

@@ -15,15 +15,19 @@ enum ImportType {
ravio,
googleAuthenticator,
aegis,
twoFas,
bitwarden,
}
class ImportCodePage extends StatelessWidget {
late List<ImportType> importOptions = [
ImportType.plainText,
ImportType.encrypted,
ImportType.ravio,
ImportType.twoFas,
ImportType.aegis,
ImportType.bitwarden,
ImportType.googleAuthenticator,
ImportType.ravio,
];
ImportCodePage({super.key});
@@ -40,6 +44,10 @@ class ImportCodePage extends StatelessWidget {
return 'Google Authenticator';
case ImportType.aegis:
return 'Aegis Authenticator';
case ImportType.twoFas:
return '2FAS Authenticator';
case ImportType.bitwarden:
return 'Bitwarden';
}
}
@@ -62,7 +70,7 @@ class ImportCodePage extends StatelessWidget {
iconButtonType: IconButtonType.secondary,
onTap: () {
Navigator.pop(context);
if(Navigator.canPop(context)) {
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
},

View File

@@ -95,7 +95,7 @@ class FaqWidget extends StatelessWidget {
),
),
),
)
),
],
),
);

View File

@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:ente_auth/app/view/app.dart';
import 'package:ente_auth/core/logging/super_logging.dart';
import 'package:ente_auth/l10n/l10n.dart';
@@ -11,6 +13,7 @@ import 'package:ente_auth/ui/components/toggle_switch_widget.dart';
import 'package:ente_auth/ui/settings/common_settings.dart';
import 'package:ente_auth/ui/settings/language_picker.dart';
import 'package:ente_auth/utils/navigation_util.dart';
import 'package:ente_auth/utils/toast_util.dart';
import 'package:flutter/material.dart';
class AdvancedSectionWidget extends StatefulWidget {
@@ -84,6 +87,9 @@ class _AdvancedSectionWidgetState extends State<AdvancedSectionWidget> {
await PreferenceService.instance.setHideCodes(
!PreferenceService.instance.shouldHideCodes(),
);
if(PreferenceService.instance.shouldHideCodes()) {
showToast(context, context.l10n.doubleTapToViewHiddenCode);
}
setState(() {});
},
),
@@ -105,6 +111,23 @@ class _AdvancedSectionWidgetState extends State<AdvancedSectionWidget> {
),
),
sectionOptionSpacing,
if (Platform.isAndroid) ...[
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: l10n.minimizeAppOnCopy,
),
trailingWidget: ToggleSwitchWidget(
value: () => PreferenceService.instance.shouldMinimizeOnCopy(),
onChanged: () async {
await PreferenceService.instance.setShouldMinimizeOnCopy(
!PreferenceService.instance.shouldMinimizeOnCopy(),
);
setState(() {});
},
),
),
sectionOptionSpacing,
],
MenuItemWidget(
captionedTextWidget: CaptionedTextWidget(
title: l10n.crashAndErrorReporting,

View File

@@ -1,5 +1,4 @@
import 'dart:io';
import 'package:dotted_border/dotted_border.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/models/subscription.dart';
@@ -37,36 +36,46 @@ class SupportDevWidget extends StatelessWidget {
}
}
GestureDetector buildWidget(AppLocalizations l10n, BuildContext context) {
Widget buildWidget(AppLocalizations l10n, BuildContext context) {
return GestureDetector(
onTap: () {
launchUrl(Uri.parse("https://ente.io"));
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
text: l10n.supportDevs,
style: getEnteTextTheme(context).large,
tags: {
'bold-green': StyledTextTag(
style: TextStyle(
fontWeight: FontWeight.bold,
color: getEnteColorScheme(context).primaryGreen,
child: DottedBorder(
borderType: BorderType.RRect,
radius: const Radius.circular(12),
padding: const EdgeInsets.all(6),
dashPattern: const <double>[3, 3],
color: getEnteColorScheme(context).primaryGreen,
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
text: l10n.supportDevs,
style: getEnteTextTheme(context).large,
tags: {
'bold-green': StyledTextTag(
style: TextStyle(
fontWeight: FontWeight.bold,
color: getEnteColorScheme(context).primaryGreen,
),
),
},
),
const Padding(padding: EdgeInsets.all(6)),
Text(
l10n.supportDiscount,
style: const TextStyle(
color: Colors.grey,
),
),
},
],
),
const Padding(padding: EdgeInsets.all(6)),
Text(
l10n.supportDiscount,
style: const TextStyle(
color: Colors.grey,
),
),
],
),
),
),
);

View File

@@ -8,6 +8,7 @@ import 'package:ente_auth/ui/settings/common_settings.dart';
import 'package:ente_auth/ui/settings/faq.dart';
import 'package:ente_auth/utils/email_util.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:url_launcher/url_launcher_string.dart';
class SupportSectionWidget extends StatefulWidget {
@@ -90,8 +91,12 @@ class _SupportSectionWidgetState extends State<SupportSectionWidget> {
await sendLogs(context, l10n.reportBug, "auth@ente.io");
},
onDoubleTap: () async {
final zipFilePath = await getZippedLogsFile(context);
await shareLogs(context, "auth@ente.io", zipFilePath);
try {
final zipFilePath = await getZippedLogsFile(context);
await shareLogs(context, "auth@ente.io", zipFilePath);
} catch (e) {
Logger("SupportSectionWidget").severe("failed to export logs", e);
}
},
),
sectionOptionSpacing,

View File

@@ -3,7 +3,9 @@ import 'dart:io';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/onboarding/view/onboarding_page.dart';
import 'package:ente_auth/services/local_authentication_service.dart';
import 'package:ente_auth/services/user_service.dart';
import 'package:ente_auth/store/code_store.dart';
import 'package:ente_auth/theme/colors.dart';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
@@ -99,6 +101,19 @@ class SettingsPage extends StatelessWidget {
await handleExportClick(context);
} else {
if (result.action == ButtonAction.second) {
bool hasCodes =
(await CodeStore.instance.getAllCodes()).isNotEmpty;
if (hasCodes) {
final hasAuthenticated = await LocalAuthenticationService
.instance
.requestLocalAuthentication(
context,
context.l10n.authToInitiateSignIn,
);
if (!hasAuthenticated) {
return;
}
}
await routeToPage(
context,
const OnboardingPage(),

View File

@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:ente_auth/l10n/l10n.dart';
import 'package:ente_auth/ui/common/gradient_button.dart';
import 'package:ente_auth/ui/tools/app_lock.dart';
import 'package:ente_auth/utils/auth_util.dart';
@@ -13,13 +14,25 @@ class LockScreen extends StatefulWidget {
State<LockScreen> createState() => _LockScreenState();
}
class _LockScreenState extends State<LockScreen> {
class _LockScreenState extends State<LockScreen> with WidgetsBindingObserver {
final _logger = Logger("LockScreen");
bool _isShowingLockScreen = false;
bool _hasPlacedAppInBackground = false;
bool _hasAuthenticationFailed = false;
int? lastAuthenticatingTime;
@override
void initState() {
_showLockScreen();
_logger.info("initiatingState");
super.initState();
WidgetsBinding.instance.addObserver(this);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (isNonMobileIOSDevice()) {
_logger.info('ignore init for non mobile iOS device');
return;
}
_showLockScreen(source: "postFrameInit");
});
}
@override
@@ -34,16 +47,16 @@ class _LockScreenState extends State<LockScreen> {
alignment: Alignment.center,
children: [
Opacity(
opacity: 0.3,
opacity: 0.2,
child: Image.asset('assets/loading_photos_background.png'),
),
SizedBox(
width: 142,
width: 180,
child: GradientButton(
text: "Unlock",
text: context.l10n.unlock,
iconData: Icons.lock_open_outlined,
onTap: () async {
_showLockScreen();
_showLockScreen(source: "tapUnlock");
},
),
),
@@ -55,16 +68,76 @@ class _LockScreenState extends State<LockScreen> {
);
}
Future<void> _showLockScreen() async {
_logger.info("Showing lockscreen");
bool isNonMobileIOSDevice() {
if (Platform.isAndroid) {
return false;
}
var shortestSide = MediaQuery.of(context).size.shortestSide;
return shortestSide > 600 ? true : false;
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
_logger.info(state.toString());
if (state == AppLifecycleState.resumed && !_isShowingLockScreen) {
// This is triggered either when the lock screen is dismissed or when
// the app is brought to foreground
_hasPlacedAppInBackground = false;
final bool didAuthInLast5Seconds = lastAuthenticatingTime != null &&
DateTime.now().millisecondsSinceEpoch - lastAuthenticatingTime! <
5000;
if (!_hasAuthenticationFailed && !didAuthInLast5Seconds) {
// Show the lock screen again only if the app is resuming from the
// background, and not when the lock screen was explicitly dismissed
Future.delayed(
Duration.zero,
() => _showLockScreen(source: "lifeCycle"),
);
} else {
_hasAuthenticationFailed = false; // Reset failure state
}
} else if (state == AppLifecycleState.paused ||
state == AppLifecycleState.inactive) {
// This is triggered either when the lock screen pops up or when
// the app is pushed to background
if (!_isShowingLockScreen) {
_hasPlacedAppInBackground = true;
_hasAuthenticationFailed = false; // reset failure state
}
}
}
@override
void dispose() {
_logger.info('disposing');
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Future<void> _showLockScreen({String source = ''}) async {
final int id = DateTime.now().millisecondsSinceEpoch;
_logger.info("Showing lock screen $source $id");
try {
_isShowingLockScreen = true;
final result = await requestAuthentication(
"Please authenticate to view your secrets",
context,
context.l10n.authToViewSecrets,
);
_logger.finest("LockScreen Result $result $id");
_isShowingLockScreen = false;
if (result) {
lastAuthenticatingTime = DateTime.now().millisecondsSinceEpoch;
AppLock.of(context)!.didUnlock();
} else {
if (!_hasPlacedAppInBackground) {
// Treat this as a failure only if user did not explicitly
// put the app in background
_hasAuthenticationFailed = true;
_logger.info("Authentication failed");
}
}
} catch (e, s) {
_isShowingLockScreen = false;
_logger.severe(e, s);
}
}

View File

@@ -1,9 +1,10 @@
import 'dart:convert';
import 'package:ente_auth/theme/ente_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/svg.dart';
import 'package:logging/logging.dart';
class IconUtils {
IconUtils._privateConstructor();
@@ -19,6 +20,7 @@ class IconUtils {
}
Widget getIcon(
BuildContext context,
String provider, {
double width = 24,
}) {
@@ -37,6 +39,20 @@ class IconUtils {
_simpleIcons[title],
width,
);
} else if (title.isNotEmpty) {
bool showLargeIcon = width > 24;
return CircleAvatar(
radius: width / 2,
backgroundColor: getEnteColorScheme(context).avatarColors[
title.hashCode % getEnteColorScheme(context).avatarColors.length],
child: Text(
title.toUpperCase()[0],
// fixed color
style: showLargeIcon
? getEnteTextTheme(context).h3Bold.copyWith(color: Colors.white)
: getEnteTextTheme(context).body.copyWith(color: Colors.white),
),
);
} else {
return const SizedBox.shrink();
}
@@ -62,25 +78,43 @@ class IconUtils {
}
Future<void> _loadJson() async {
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"];
}
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(
icon["slug"],
icon["hex"],
);
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()
.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()
.replaceAll(' ', '')
.toLowerCase()] = CustomIconData(
icon["slug"],
icon["hex"],
);
if (icon["altNames"] != null) {
for (final name in icon["altNames"]) {
_customIcons[name] = CustomIconData(
icon["slug"],
icon["hex"],
);
}
}
}
} catch (e) {
Logger("IconUtils").severe("Error loading icons", e);
}
}
String _getProviderTitle(String provider) {
return provider.split(RegExp(r'[.(]'))[0].trim().toLowerCase();
return provider.split(RegExp(r'[.(]'))[0].replaceAll(' ', '').toLowerCase();
}
}

View File

@@ -1,25 +1,37 @@
import 'package:ente_auth/l10n/l10n.dart';
import 'package:flutter/cupertino.dart';
import 'package:local_auth/local_auth.dart';
import 'package:local_auth_android/local_auth_android.dart';
import 'package:local_auth_ios/types/auth_messages_ios.dart';
import 'package:logging/logging.dart';
Future<bool> requestAuthentication(String reason) async {
Future<bool> requestAuthentication(BuildContext context, String reason) async {
Logger("AuthUtil").info("Requesting authentication");
await LocalAuthentication().stopAuthentication();
final l10n = context.l10n;
return await LocalAuthentication().authenticate(
localizedReason: reason,
authMessages: [
const AndroidAuthMessages(
biometricHint: "Verify identity",
biometricNotRecognized: "Not recognized, try again",
biometricRequiredTitle: "Biometric required",
biometricSuccess: "Successfully verified",
cancelButton: "Cancel",
deviceCredentialsRequiredTitle: "Device credentials required",
deviceCredentialsSetupDescription: "Device credentials required",
goToSettingsButton: "Go to settings",
goToSettingsDescription:
"Authentication is not setup on your device, go to Settings > Security to set it up",
signInTitle: "Authentication required",
AndroidAuthMessages(
biometricHint: l10n.androidBiometricHint,
biometricNotRecognized: l10n.androidBiometricNotRecognized,
biometricRequiredTitle: l10n.androidBiometricRequiredTitle,
biometricSuccess: l10n.androidBiometricSuccess,
cancelButton: l10n.androidCancelButton,
deviceCredentialsRequiredTitle:
l10n.androidDeviceCredentialsRequiredTitle,
deviceCredentialsSetupDescription:
l10n.androidDeviceCredentialsSetupDescription,
goToSettingsButton: l10n.goToSettings,
goToSettingsDescription: l10n.androidGoToSettingsDescription,
signInTitle: l10n.androidSignInTitle,
),
IOSAuthMessages(
goToSettingsButton: l10n.goToSettings,
goToSettingsDescription: l10n.goToSettings,
lockOut: l10n.iOSLockOut,
// cancelButton default value is "Ok"
cancelButton: l10n.iOSOkButton,
),
],
);

View File

@@ -42,8 +42,8 @@ Uint8List cryptoPwHash(Map<String, dynamic> args) {
}
Uint8List cryptoKdfDeriveFromKey(
Map<String, dynamic> args,
) {
Map<String, dynamic> args,
) {
return Sodium.cryptoKdfDeriveFromKey(
args["subkeyLen"],
args["subkeyId"],
@@ -58,7 +58,7 @@ Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
final sourceFileLength = await sourceFile.length();
final inputFile = sourceFile.openSync(mode: io.FileMode.read);
final state =
Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
var bytesRead = 0;
bool isDone = false;
while (!isDone) {
@@ -77,7 +77,7 @@ Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
EncryptionResult chachaEncryptData(Map<String, dynamic> args) {
final initPushResult =
Sodium.cryptoSecretstreamXchacha20poly1305InitPush(args["key"]);
Sodium.cryptoSecretstreamXchacha20poly1305InitPush(args["key"]);
final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
initPushResult.state,
args["source"],
@@ -102,7 +102,7 @@ Future<EncryptionResult> chachaEncryptFile(Map<String, dynamic> args) async {
final inputFile = sourceFile.openSync(mode: io.FileMode.read);
final key = args["key"] ?? Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
final initPushResult =
Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
var bytesRead = 0;
var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;
while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
@@ -156,7 +156,7 @@ Future<void> chachaDecryptFile(Map<String, dynamic> args) async {
final buffer = await inputFile.read(chunkSize);
bytesRead += chunkSize;
final pullResult =
Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null);
Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, buffer, null);
await destinationFile.writeAsBytes(pullResult.m, mode: io.FileMode.append);
tag = pullResult.tag;
}
@@ -190,20 +190,22 @@ class CryptoUtil {
Sodium.init();
}
static Uint8List base642bin(String b64, {
static Uint8List base642bin(
String b64, {
String? ignore,
int variant = Sodium.base64VariantOriginal,
}) {
return Sodium.base642bin(b64, ignore: ignore, variant: variant);
}
static String bin2base64(Uint8List bin, {
static String bin2base64(
Uint8List bin, {
bool urlSafe = false,
}) {
return Sodium.bin2base64(
bin,
variant:
urlSafe ? Sodium.base64VariantUrlsafe : Sodium.base64VariantOriginal,
urlSafe ? Sodium.base64VariantUrlsafe : Sodium.base64VariantOriginal,
);
}
@@ -237,9 +239,11 @@ class CryptoUtil {
// Decrypts the given cipher, with the given key and nonce using XSalsa20
// (w Poly1305 MAC).
static Future<Uint8List> decrypt(Uint8List cipher,
Uint8List key,
Uint8List nonce,) async {
static Future<Uint8List> decrypt(
Uint8List cipher,
Uint8List key,
Uint8List nonce,
) async {
final args = <String, dynamic>{};
args["cipher"] = cipher;
args["nonce"] = nonce;
@@ -256,9 +260,11 @@ class CryptoUtil {
// This function runs on the same thread as the caller, so should be used only
// for small amounts of data where thread switching can result in a degraded
// user experience
static Uint8List decryptSync(Uint8List cipher,
Uint8List key,
Uint8List nonce,) {
static Uint8List decryptSync(
Uint8List cipher,
Uint8List key,
Uint8List nonce,
) {
final args = <String, dynamic>{};
args["cipher"] = cipher;
args["nonce"] = nonce;
@@ -270,8 +276,10 @@ class CryptoUtil {
// nonce, using XChaCha20 (w Poly1305 MAC).
// This function runs on the isolate pool held by `_computer`.
// TODO: Remove "ChaCha", an implementation detail from the function name
static Future<EncryptionResult> encryptChaCha(Uint8List source,
Uint8List key,) async {
static Future<EncryptionResult> encryptChaCha(
Uint8List source,
Uint8List key,
) async {
final args = <String, dynamic>{};
args["source"] = source;
args["key"] = key;
@@ -285,9 +293,11 @@ class CryptoUtil {
// Decrypts the given source, with the given key and header using XChaCha20
// (w Poly1305 MAC).
// TODO: Remove "ChaCha", an implementation detail from the function name
static Future<Uint8List> decryptChaCha(Uint8List source,
Uint8List key,
Uint8List header,) async {
static Future<Uint8List> decryptChaCha(
Uint8List source,
Uint8List key,
Uint8List header,
) async {
final args = <String, dynamic>{};
args["source"] = source;
args["key"] = key;
@@ -304,10 +314,10 @@ class CryptoUtil {
// to the destinationFilePath.
// If a key is not provided, one is generated and returned.
static Future<EncryptionResult> encryptFile(
String sourceFilePath,
String destinationFilePath, {
Uint8List? key,
}) {
String sourceFilePath,
String destinationFilePath, {
Uint8List? key,
}) {
final args = <String, dynamic>{};
args["sourceFilePath"] = sourceFilePath;
args["destinationFilePath"] = destinationFilePath;
@@ -322,10 +332,11 @@ class CryptoUtil {
// Decrypts the file at sourceFilePath, with the given key and header using
// XChaCha20 (w Poly1305 MAC), and writes it to the destinationFilePath.
static Future<void> decryptFile(
String sourceFilePath,
String destinationFilePath,
Uint8List header,
Uint8List key,) {
String sourceFilePath,
String destinationFilePath,
Uint8List header,
Uint8List key,
) {
final args = <String, dynamic>{};
args["sourceFilePath"] = sourceFilePath;
args["destinationFilePath"] = destinationFilePath;
@@ -356,10 +367,10 @@ class CryptoUtil {
// Decrypts the input using the given publicKey-secretKey pair
static Uint8List openSealSync(
Uint8List input,
Uint8List publicKey,
Uint8List secretKey,
) {
Uint8List input,
Uint8List publicKey,
Uint8List secretKey,
) {
return Sodium.cryptoBoxSealOpen(input, publicKey, secretKey);
}
@@ -377,9 +388,9 @@ class CryptoUtil {
// At all points, we ensure that the product of these two variables (the area
// under the graph that determines the amount of work required) is a constant.
static Future<DerivedKeyResult> deriveSensitiveKey(
Uint8List password,
Uint8List salt,
) async {
Uint8List password,
Uint8List salt,
) async {
final logger = Logger("pwhash");
int memLimit = Sodium.cryptoPwhashMemlimitSensitive;
int opsLimit = Sodium.cryptoPwhashOpslimitSensitive;
@@ -407,7 +418,10 @@ class CryptoUtil {
return DerivedKeyResult(key, memLimit, opsLimit);
} catch (e, s) {
logger.warning(
"failed to deriveKey mem: $memLimit, ops: $opsLimit", e, s,);
"failed to deriveKey mem: $memLimit, ops: $opsLimit",
e,
s,
);
}
memLimit = (memLimit / 2).round();
opsLimit = opsLimit * 2;
@@ -421,9 +435,9 @@ class CryptoUtil {
// extra layer of authentication (atop the access token and collection key).
// More details @ https://ente.io/blog/building-shareable-links/
static Future<DerivedKeyResult> deriveInteractiveKey(
Uint8List password,
Uint8List salt,
) async {
Uint8List password,
Uint8List salt,
) async {
final int memLimit = Sodium.cryptoPwhashMemlimitInteractive;
final int opsLimit = Sodium.cryptoPwhashOpslimitInteractive;
final key = await deriveKey(password, salt, memLimit, opsLimit);
@@ -433,13 +447,13 @@ class CryptoUtil {
// Derives a key for a given password, salt, memLimit and opsLimit using
// Argon2id, v1.3.
static Future<Uint8List> deriveKey(
Uint8List password,
Uint8List salt,
int memLimit,
int opsLimit,
) {
Uint8List password,
Uint8List salt,
int memLimit,
int opsLimit,
) async {
try {
return _computer.compute(
return await _computer.compute(
cryptoPwHash,
param: {
"password": password,
@@ -449,7 +463,7 @@ class CryptoUtil {
},
taskName: "deriveKey",
);
} catch(e,s) {
} catch (e, s) {
final String errMessage = 'failed to deriveKey memLimit: $memLimit and '
'opsLimit: $opsLimit';
Logger("CryptoUtilDeriveKey").warning(errMessage, e, s);
@@ -461,20 +475,25 @@ class CryptoUtil {
// (Key Derivation Function) with the `loginSubKeyId` and
// `loginSubKeyLen` and `loginSubKeyContext` as context
static Future<Uint8List> deriveLoginKey(
Uint8List key,
) async {
final Uint8List derivedKey = await _computer.compute(
cryptoKdfDeriveFromKey,
param: {
"key": key,
"subkeyId": loginSubKeyId,
"subkeyLen": loginSubKeyLen,
"context": utf8.encode(loginSubKeyContext),
},
taskName: "deriveLoginKey",
);
// return the first 16 bytes of the derived key
return derivedKey.sublist(0, 16);
Uint8List key,
) async {
try {
final Uint8List derivedKey = await _computer.compute(
cryptoKdfDeriveFromKey,
param: {
"key": key,
"subkeyId": loginSubKeyId,
"subkeyLen": loginSubKeyLen,
"context": utf8.encode(loginSubKeyContext),
},
taskName: "deriveLoginKey",
);
// return the first 16 bytes of the derived key
return derivedKey.sublist(0, 16);
} catch (e, s) {
Logger("deriveLoginKey").severe("loginKeyDerivation failed", e, s);
throw LoginKeyDerivationError();
}
}
// Computes and returns the hash of the source file

View File

@@ -27,7 +27,7 @@ late Set<String> iOSLowEndMachineCodes = <String>{
"iPhone10,2", // iPhone 8 Plus
"iPhone10,3", // iPhone X Global
"iPhone10,4", // iPhone 8
"iPhone10,5" // iPhone 8
"iPhone10,5", // iPhone 8
};
Future<bool> isLowSpecDevice() async {

View File

@@ -13,9 +13,11 @@ import 'package:ente_auth/ui/tools/debug/log_file_viewer.dart';
// import 'package:ente_auth/ui/tools/debug/log_file_viewer.dart';
import 'package:ente_auth/utils/dialog_util.dart';
import 'package:ente_auth/utils/toast_util.dart';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:intl/intl.dart';
import 'package:logging/logging.dart';
// import 'package:open_mail_app/open_mail_app.dart';
import 'package:package_info_plus/package_info_plus.dart';
@@ -198,9 +200,26 @@ Future<void> shareLogs(
],
);
if (result?.action != null && result!.action == ButtonAction.second) {
final Size size = MediaQuery.of(context).size;
await Share.shareFiles(
[zipFilePath],
await exportLogs(context, zipFilePath);
}
}
Future<void> exportLogs(BuildContext context, String zipFilePath) async {
final Size size = MediaQuery.of(context).size;
if (Platform.isAndroid) {
DateTime now = DateTime.now().toUtc();
String shortMonthName = DateFormat('MMM').format(now); // Short month name
String logFileName =
'ente-logs-${now.year}-$shortMonthName-${now.day}-${now.hour}-${now.minute}';
await FileSaver.instance.saveAs(
name: logFileName,
filePath: zipFilePath,
mimeType: MimeType.zip,
ext: 'zip',
);
} else {
await Share.shareXFiles(
[XFile(zipFilePath, mimeType: 'application/zip')],
sharePositionOrigin: Rect.fromLTWH(0, 0, size.width, size.height / 2),
);
}
@@ -277,7 +296,7 @@ void _showNoMailAppsDialog(BuildContext context, String toEmail) {
onPressed: () {
Navigator.pop(context);
},
)
),
],
);
},

View File

@@ -6,11 +6,15 @@
#include "generated_plugin_registrant.h"
#include <file_saver/file_saver_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <sentry_flutter/sentry_flutter_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_saver_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin");
file_saver_plugin_register_with_registrar(file_saver_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);

View File

@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
file_saver
flutter_secure_storage_linux
sentry_flutter
url_launcher_linux

View File

@@ -7,12 +7,13 @@ import Foundation
import connectivity_macos
import device_info_plus
import file_saver
import flutter_local_notifications
import flutter_secure_storage_macos
import package_info_plus
import path_provider_foundation
import sentry_flutter
import share_plus_macos
import share_plus
import shared_preferences_foundation
import sqflite
import url_launcher_macos
@@ -20,6 +21,7 @@ import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))

View File

@@ -10,6 +10,9 @@ A user on GitHub has written a guide to export our data from Authy (morpheus on
## Exporting from Authy
To export your data, please follow [this guide](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93). This will create a new JSON file with all your Authy TOTP data in it. **Do not share this file with anyone!**
Or, you can [use this tool by Neeraj](https://github.com/ua741/authy-export/releases/tag/v0.0.4) to simplify things and skip to importing to ente Authenticator.
### *Do note that these tools may not export ALL of your codes. Make sure that all your accounts have been imported successfully before deleting any codes from your Authy account!*
## Converting the export for ente Authenticator
So now that you have the JSON file, does that mean it can be imported into ente Authenticator? Nope.
@@ -17,7 +20,7 @@ This is because the code in the guide exports your Authy data for Bitwarden, not
<img width="454" alt="ente Authenticator Screenshot" src="https://github.com/gweeeen/auth/assets/41323182/30566a69-cfa0-4de0-9f0d-95967d4c5cad">
So, this means that even if you try to import this file, nothing will happen. But don't worry, I've written a program in Python that converts the JSON file into a TXT file that ente Authenticator can use!
So, this means that even if you try to import this file, nothing will happen. But don't worry, I've written a program in Python that converts the JSON file into a TXT file that ente Authenticator can use! (It's definitely not written **professionaly**, but hey it gets the job done so I'm happy with that.)
You can download my program [here](https://github.com/gweeeen/ducky/blob/main/duckys_other_stuff/authy_to_ente.py). Or if you **really like making life hard**, then you can make a new Python file and copy this code to it:

View File

@@ -418,6 +418,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.3.1"
file_saver:
dependency: "direct main"
description:
name: file_saver
sha256: "591d25e750e3a4b654f7b0293abc2ed857242f82ca7334051b2a8ceeb369dac8"
url: "https://pub.dev"
source: hosted
version: "0.2.8"
fixnum:
dependency: transitive
description:
@@ -447,6 +455,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.3"
flutter_displaymode:
dependency: "direct main"
description:
name: flutter_displaymode
sha256: "42c5e9abd13d28ed74f701b60529d7f8416947e58256e6659c5550db719c57ef"
url: "https://pub.dev"
source: hosted
version: "0.6.0"
flutter_email_sender:
dependency: "direct main"
description:
@@ -667,10 +683,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev"
source: hosted
version: "0.13.6"
version: "1.1.0"
http_multi_server:
dependency: transitive
description:
@@ -747,12 +763,12 @@ packages:
dependency: "direct main"
description:
name: local_auth
sha256: "0cf238be2bfa51a6c9e7e9cfc11c05ea39f2a3a4d3e5bb255d0ebc917da24401"
sha256: "7e6c63082e399b61e4af71266b012e767a5d4525dd6e9ba41e174fd42d76e115"
url: "https://pub.dev"
source: hosted
version: "2.1.6"
version: "2.1.7"
local_auth_android:
dependency: transitive
dependency: "direct main"
description:
name: local_auth_android
sha256: "523dd636ce061ddb296cbc3db410cb8f21efb7d8798f7b9532c8038ce2f8bad5"
@@ -760,7 +776,7 @@ packages:
source: hosted
version: "1.0.31"
local_auth_ios:
dependency: transitive
dependency: "direct main"
description:
name: local_auth_ios
sha256: edc2977c5145492f3451db9507a2f2f284ee4f408950b3e16670838726761940
@@ -1031,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:
@@ -1115,50 +1139,18 @@ packages:
dependency: "direct main"
description:
name: share_plus
sha256: f582d5741930f3ad1bf0211d358eddc0508cc346e5b4b248bd1e569c995ebb7a
sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd
url: "https://pub.dev"
source: hosted
version: "4.5.3"
share_plus_linux:
dependency: transitive
description:
name: share_plus_linux
sha256: dc32bf9f1151b9864bb86a997c61a487967a08f2e0b4feaa9a10538712224da4
url: "https://pub.dev"
source: hosted
version: "3.0.1"
share_plus_macos:
dependency: transitive
description:
name: share_plus_macos
sha256: "44daa946f2845045ecd7abb3569b61cd9a55ae9cc4cbec9895b2067b270697ae"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "7.2.1"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981"
sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956
url: "https://pub.dev"
source: hosted
version: "3.2.1"
share_plus_web:
dependency: transitive
description:
name: share_plus_web
sha256: eaef05fa8548b372253e772837dd1fbe4ce3aca30ea330765c945d7d4f7c9935
url: "https://pub.dev"
source: hosted
version: "3.1.0"
share_plus_windows:
dependency: transitive
description:
name: share_plus_windows
sha256: "3a21515ae7d46988d42130cd53294849e280a5de6ace24bae6912a1bffd757d4"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.3.1"
shared_preferences:
dependency: "direct main"
description:
@@ -1646,4 +1638,4 @@ packages:
version: "3.1.2"
sdks:
dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=3.7.0"
flutter: ">=3.10.0"

Some files were not shown because too many files have changed in this diff Show More