1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00:00

Merge branch 'master' of https://github.com/bitwarden/clients into tools/pm-147/import-error-states-usability-improvements

This commit is contained in:
Daniel James Smith
2023-07-25 17:46:59 +02:00
186 changed files with 15827 additions and 2803 deletions

2
.github/CODEOWNERS vendored
View File

@@ -13,7 +13,7 @@ bitwarden_license/bit-web/src/app/secrets-manager @bitwarden/team-secrets-manage
apps/browser/src/auth @bitwarden/team-auth-dev
apps/cli/src/auth @bitwarden/team-auth-dev
apps/desktop/src/auth @bitwarden/team-auth-dev
apps/web/src/auth @bitwarden/team-auth-dev
apps/web/src/app/auth @bitwarden/team-auth-dev
# web connectors used for auth
apps/web/src/connectors @bitwarden/team-auth-dev
bitwarden_license/bit-web/src/app/auth @bitwarden/team-auth-dev

View File

@@ -145,8 +145,8 @@ jobs:
- name: Build
run: npm run dist
- name: Build Manifest v3
run: npm run dist:mv3
# - name: Build Manifest v3
# run: npm run dist:mv3
- name: Gulp
run: gulp ci
@@ -179,12 +179,12 @@ jobs:
path: apps/browser/dist/dist-opera.zip
if-no-files-found: error
- name: Upload Opera MV3 artifact
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
with:
name: dist-opera-MV3-${{ env._BUILD_NUMBER }}.zip
path: apps/browser/dist/dist-opera-mv3.zip
if-no-files-found: error
# - name: Upload Opera MV3 artifact
# uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
# with:
# name: dist-opera-MV3-${{ env._BUILD_NUMBER }}.zip
# path: apps/browser/dist/dist-opera-mv3.zip
# if-no-files-found: error
- name: Upload Chrome artifact
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
@@ -193,12 +193,12 @@ jobs:
path: apps/browser/dist/dist-chrome.zip
if-no-files-found: error
- name: Upload Chrome MV3 artifact
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
with:
name: dist-chrome-MV3-${{ env._BUILD_NUMBER }}.zip
path: apps/browser/dist/dist-chrome-mv3.zip
if-no-files-found: error
# - name: Upload Chrome MV3 artifact
# uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
# with:
# name: dist-chrome-MV3-${{ env._BUILD_NUMBER }}.zip
# path: apps/browser/dist/dist-chrome-mv3.zip
# if-no-files-found: error
- name: Upload Firefox artifact
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
@@ -214,12 +214,12 @@ jobs:
path: apps/browser/dist/dist-edge.zip
if-no-files-found: error
- name: Upload Edge MV3 artifact
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
with:
name: dist-edge-MV3-${{ env._BUILD_NUMBER }}.zip
path: apps/browser/dist/dist-edge-mv3.zip
if-no-files-found: error
# - name: Upload Edge MV3 artifact
# uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
# with:
# name: dist-edge-MV3-${{ env._BUILD_NUMBER }}.zip
# path: apps/browser/dist/dist-edge-mv3.zip
# if-no-files-found: error
- name: Upload browser source
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2

View File

@@ -243,7 +243,7 @@ jobs:
shell: pwsh
run: |
cd dist
choco push
choco push --source=https://push.chocolatey.org/
npm:
name: Publish NPM

View File

@@ -1,6 +1,6 @@
{
"name": "@bitwarden/browser",
"version": "2023.7.0",
"version": "2023.7.1",
"scripts": {
"build": "webpack",
"build:mv3": "cross-env MANIFEST_VERSION=3 webpack",

View File

@@ -0,0 +1,4 @@
/* eslint-disable no-undef */
module.exports = {
plugins: [require("tailwindcss"), require("autoprefixer"), require("postcss-nested")],
};

View File

@@ -2236,10 +2236,10 @@
"description": "United States"
},
"accessDenied": {
"message": "Достъпът е отказан. Нямате право за преглед на тази страница."
"message": "Отказан достъп. Нямате право за преглед на страницата."
},
"general": {
"message": "General"
"message": "Общи"
},
"display": {
"message": "Display"

View File

@@ -2242,6 +2242,6 @@
"message": "General"
},
"display": {
"message": "Display"
"message": "Mostra"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2236,12 +2236,12 @@
"description": "United States"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
"message": "Ligipääs keelatud. Sul pole lubatud seda lehekülge vaadata."
},
"general": {
"message": "General"
"message": "Üldine"
},
"display": {
"message": "Display"
"message": "Kuvamine"
}
}

View File

@@ -196,7 +196,7 @@
"message": "Laguntza eta iritziak"
},
"helpCenter": {
"message": "Bitwarden Help center"
"message": "Bitwarden Laguntza zentroa"
},
"communityForums": {
"message": "Explore Bitwarden community forums"

View File

@@ -2239,9 +2239,9 @@
"message": "دسترسی رد شد. شما اجازه مشاهده این صفحه را ندارید."
},
"general": {
"message": "General"
"message": "عمومی"
},
"display": {
"message": "Display"
"message": "نمایش"
}
}

View File

@@ -288,7 +288,7 @@
"message": "Näytä"
},
"noItemsInList": {
"message": "Ei näytettäviä kohteita."
"message": "Näytettäviä kohteita ei ole."
},
"itemInformation": {
"message": "Kohteen tiedot"
@@ -2123,7 +2123,7 @@
"message": "Laitteella kirjautuminen"
},
"loginWithDeviceEnabledInfo": {
"message": "Laitteella kirjautuminen on määritettävä Bitwarden-mobiilisovelluksen asetuksista. Tarvitsetko eri vaihtoehdon?"
"message": "Laitteella kirjautuminen on määritettävä Bitwarden-sovelluksen asetuksista. Tarvitsetko eri vaihtoehdon?"
},
"fingerprintPhraseHeader": {
"message": "Tunnistelauseke"

View File

@@ -56,7 +56,7 @@
"message": "Saugykla"
},
"myVault": {
"message": "Saugykla"
"message": "Mano saugykla"
},
"allVaults": {
"message": "Visos saugyklos"
@@ -613,10 +613,10 @@
"description": "Clipboard is the operating system thing where you copy/paste data to on your device."
},
"notificationAddDesc": {
"message": "Ar Bitwarden turėtų prisiminti šį slaptažodį?"
"message": "Ar Bitwarden turėtų įsiminti šį slaptažodį už tave?"
},
"notificationAddSave": {
"message": "Taip, išsaugoti dabar"
"message": "Išsaugoti"
},
"enableChangedPasswordNotification": {
"message": "Paprašyti atnaujinti esamą prisijungimą"
@@ -625,10 +625,10 @@
"message": "Paprašyti atnaujinti prisijungimo slaptažodį, kai pakeitimas aptiktas svetainėje."
},
"notificationChangeDesc": {
"message": "Ar norite atnaujinti šį slaptažodį Bitwarden?"
"message": "Ar nori atnaujinti šį slaptažodį Bitwarden?"
},
"notificationChangeSave": {
"message": "Taip, atnaujinti dabar"
"message": "Atnaujinti"
},
"enableContextMenuItem": {
"message": "Rodyti kontekstinio meniu pasririnkimus"
@@ -658,7 +658,7 @@
"description": "Light color"
},
"solarizedDark": {
"message": "Solarized dark",
"message": "Saulėtas tamsą",
"description": "'Solarized' is a noun and the name of a color scheme. It should not be translated."
},
"exportVault": {
@@ -748,7 +748,7 @@
"message": "Priedų nėra."
},
"attachmentSaved": {
"message": "Priedas buvo išsaugotas."
"message": "Priedas išsaugotas"
},
"file": {
"message": "Failas"
@@ -757,13 +757,13 @@
"message": "Pasirinkite failą."
},
"maxFileSize": {
"message": "Failai negali būti didesni už 500 MB."
"message": "Didžiausias failo dydis 500 MB."
},
"featureUnavailable": {
"message": "Funkcija neprieinama"
},
"updateKey": {
"message": "Negalite naudoti šios funkcijos, kol neatnaujinsite šifravimo raktą."
"message": "Negali naudotis šia funkcija, kol neatnaujinsi šifravimo raktą."
},
"premiumMembership": {
"message": "Premium narystė"
@@ -781,7 +781,7 @@
"message": "Neturite Premium narystės."
},
"premiumSignUpAndGet": {
"message": "Prisijungite prie Premium narystės ir gaukite:"
"message": "Prisijunk prie Premium narystės ir gauk:"
},
"ppremiumSignUpStorage": {
"message": "1 GB užšifruotos vietos diske bylų prisegimams."
@@ -790,10 +790,10 @@
"message": "Papildomos dviejų žingsių prisijungimo opcijos, tokios kaip YubiKey, FIDO U2F ir Duo."
},
"ppremiumSignUpReports": {
"message": "Slaptažodžio higiena, prieigos sveikata ir duomenų nutekinimo ataskaitos, kad jūsų seifas būtų saugus."
"message": "Slaptažodžio higiena, prieigos sveikata ir duomenų nutekinimo ataskaitos, kad tavo saugyklas būtų saugus."
},
"ppremiumSignUpTotp": {
"message": "TOTP patvirtinimo kodų (2FA) generatorius prisijungimams prie jūsų saugyklos."
"message": "TOTP patvirtinimo kodų (2FA) generatorius prisijungimams prie tavo saugyklos."
},
"ppremiumSignUpSupport": {
"message": "Prioritetinis klientų aptarnavimas."
@@ -802,13 +802,13 @@
"message": "Visos būsimos Premium savybės. Daugiau jau greitai!"
},
"premiumPurchase": {
"message": "Įsigyti Premium planą"
"message": "Įsigyti Premium"
},
"premiumPurchaseAlert": {
"message": "Jūs galite įsigyti Premium narystę bitwarden.com puslapyje. Ar norite aplankyti šį puslapį dabar?"
"message": "Gali įsigyti Premium narystę bitwarden.com interneto saugykloje. Ar nori aplankyti svetainėje dabar?"
},
"premiumCurrentMember": {
"message": "Jūs esate Premium narys!"
"message": "Tu esi Premium narys!"
},
"premiumCurrentMemberThanks": {
"message": "Dėkojame, kad remiate Bitwarden."
@@ -835,16 +835,16 @@
"message": "Paleidžiant patvirtinti biometrinius duomenis"
},
"premiumRequired": {
"message": "Tik su Premium naryste"
"message": "Premium reikalinga"
},
"premiumRequiredDesc": {
"message": "Premium narystė reikalinga šiai funkcijai naudoti."
},
"enterVerificationCodeApp": {
"message": "Įveskite 6 skaitmenų patvirtinimo kodą iš jūsų autentifikavimo aplikacijos."
"message": "Įvesk 6 skaitmenų patvirtinimo kodą iš tavo autentifikavimo aplikacijos."
},
"enterVerificationCodeEmail": {
"message": "Įveskite 6 skaitmenų prisijungimo kodą, kuris buvo išsiųstas $EMAIL$ el. paštu.",
"message": "Įvesk 6 skaitmenų prisijungimo kodą, kuris buvo išsiųstas $EMAIL$ el. paštu.",
"placeholders": {
"email": {
"content": "$1",
@@ -871,34 +871,34 @@
"message": "Naudoti dar vieną dviejų žingsnių prisijungimo metodą"
},
"insertYubiKey": {
"message": "Insert your YubiKey into your computer's USB port, then touch its button."
"message": "Įkišk YubiKey į savo kompiuterio USB prievadą, tada paliesk jo mygtuką."
},
"insertU2f": {
"message": "Insert your security key into your computer's USB port. If it has a button, touch it."
"message": "Įkišk savo saugos raktą į kompiuterio USB prievadą. Jei jame yra mygtukas, paliesk jį."
},
"webAuthnNewTab": {
"message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab."
"message": "Norint pradėti WebAuthn 2FA patikrinimą. Spustelėk toliau esantį mygtuką, kad atsidarytų naujas skirtukas, ir sek naujame skirtuke pateiktas instrukcijas."
},
"webAuthnNewTabOpen": {
"message": "Atidaryti naują skirtuką"
},
"webAuthnAuthenticate": {
"message": "Authenticate WebAuthn"
"message": "Autentifikuoti WebAuthn"
},
"loginUnavailable": {
"message": "Prisijungimas nepasiekiamas"
},
"noTwoStepProviders": {
"message": "This account has two-step login set up, however, none of the configured two-step providers are supported by this web browser."
"message": "Šioje paskyroje nustatytas dviejų žingsnių prisijungimas, tačiau, nė vienas iš sukonfigūruotų dviejų žingsnių paslaugų teikėjų nėra palaikomas šioje interneto naršyklėje."
},
"noTwoStepProviders2": {
"message": "Please use a supported web browser (such as Chrome) and/or add additional providers that are better supported across web browsers (such as an authenticator app)."
"message": "Prašome naudoti palaikomą interneto naršyklę (pvz., Chrome) ir/arba pridėti papildomus paslaugų teikėjus, kurie geriau palaikomi įvairiose interneto naršyklėse (pvz., autentifikavimo programėlę)."
},
"twoStepOptions": {
"message": "Dviejų žingsnių prisijungimo parinktys"
},
"recoveryCodeDesc": {
"message": "Lost access to all of your two-factor providers? Use your recovery code to turn off all two-factor providers from your account."
"message": "Praradai prieigą prie visų savo dviejų veiksnių teikėjų? Naudok atkūrimo kodą, kad iš savo paskyros išjungtum visus dviejų veiksnių teikėjus."
},
"recoveryCodeTitle": {
"message": "Atkūrimo kodas"
@@ -907,46 +907,46 @@
"message": "Autentifikavimo programa"
},
"authenticatorAppDesc": {
"message": "Use an authenticator app (such as Authy or Google Authenticator) to generate time-based verification codes.",
"message": "Naudok autentifikatoriaus programėlę (pvz., Authy arba Google Autentifikatorius), kad sugeneruotum laiko patikrinimo kodus.",
"description": "'Authy' and 'Google Authenticator' are product names and should not be translated."
},
"yubiKeyTitle": {
"message": "YubiKey OTP Security Key"
"message": "YubiKey OTP saugumo raktas"
},
"yubiKeyDesc": {
"message": "Use a YubiKey to access your account. Works with YubiKey 4, 4 Nano, 4C, and NEO devices."
"message": "Naudok YubiKey, kad prisijungtum prie savo paskyros. Veikia su YubiKey 4, 4 Nano, 4C ir NEO įrenginiais."
},
"duoDesc": {
"message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.",
"message": "Patvirtink su Duo Security naudodami Duo Mobile programą, SMS žinutę, telefono skambutį arba U2F saugumo raktą.",
"description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated."
},
"duoOrganizationDesc": {
"message": "Verify with Duo Security for your organization using the Duo Mobile app, SMS, phone call, or U2F security key.",
"message": "Patikrink su Duo Security savo organizacijai naudodamasis Duo Mobile programą, SMS žinutę, telefono skambutį arba U2F saugumo raktą.",
"description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated."
},
"webAuthnTitle": {
"message": "FIDO2 WebAuthn"
},
"webAuthnDesc": {
"message": "Use any WebAuthn compatible security key to access your account."
"message": "Naudok bet kurį WebAuthn palaikantį saugumo raktą, kad galėtum naudotis savo paskyra."
},
"emailTitle": {
"message": "El. paštas"
},
"emailDesc": {
"message": "Verification codes will be emailed to you."
"message": "Patvirtinimo kodai bus atsiųsti el. paštu tau."
},
"selfHostedEnvironment": {
"message": "Self-hosted environment"
"message": "Savarankiškai sukurta aplinka"
},
"selfHostedEnvironmentFooter": {
"message": "Specify the base URL of your on-premises hosted Bitwarden installation."
"message": "Nurodyk pagrindinį URL adresą savo patalpose esančio Bitwarden diegimo."
},
"customEnvironment": {
"message": "Individualizuota aplinka"
},
"customEnvironmentFooter": {
"message": "For advanced users. You can specify the base URL of each service independently."
"message": "Pažengusiems naudotojams. Galite nurodyti kiekvienos paslaugos pagrindinį URL adresą atskirai."
},
"baseUrl": {
"message": "Serverio URL"
@@ -967,13 +967,13 @@
"message": "Piktogramų serverio URL"
},
"environmentSaved": {
"message": "Environment URLs saved"
"message": "Aplinkos URL adresai išsaugoti"
},
"enableAutoFillOnPageLoad": {
"message": "Automatiškai užpildyti užsikrovus puslapiui"
},
"enableAutoFillOnPageLoadDesc": {
"message": "If a login form is detected, auto-fill when the web page loads."
"message": "Jei aptikta prisijungimo forma, automatiškai užpildyti, kai kraunamas tinklalapis."
},
"experimentalFeature": {
"message": "Compromised or untrusted websites can exploit auto-fill on page load."
@@ -2105,10 +2105,10 @@
}
},
"loginWithMasterPassword": {
"message": "Log in with master password"
"message": "Prisijungti su pagrindiniu slaptažodžiu"
},
"loggingInAs": {
"message": "Logging in as"
"message": "Prisijungimas kaip"
},
"notYou": {
"message": "Ne jūs?"
@@ -2117,13 +2117,13 @@
"message": "Ar jūs naujas čia?"
},
"rememberEmail": {
"message": "Remember email"
"message": "Prisiminti el. paštą"
},
"loginWithDevice": {
"message": "Prisijunkite naudodami įrenginį"
},
"loginWithDeviceEnabledInfo": {
"message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?"
"message": "Prisijungti su įrenginiu turi būti nustatyta Bitwarden aplikacijos nustatymuose. Reikia kito pasirinkimo?"
},
"fingerprintPhraseHeader": {
"message": "Fingerprint phrase"
@@ -2177,10 +2177,10 @@
"message": "Your organization policies have turned on auto-fill on page load."
},
"howToAutofill": {
"message": "How to auto-fill"
"message": "Kaip automatiškai užpildyti"
},
"autofillSelectInfoWithCommand": {
"message": "Select an item from this page or use the shortcut: $COMMAND$",
"message": "Pasirink elementą iš šio puslapio arba naudok trumpąjį klavišą: $COMMAND$",
"placeholders": {
"command": {
"content": "$1",
@@ -2228,20 +2228,20 @@
"message": "Opens in a new window"
},
"eu": {
"message": "EU",
"message": "ES",
"description": "European Union"
},
"us": {
"message": "US",
"message": "JAV",
"description": "United States"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
"message": "Prieiga uždrausta. Neturi teisės peržiūrėti šį puslapį."
},
"general": {
"message": "General"
"message": "Bendra"
},
"display": {
"message": "Display"
"message": "Rodyti"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2239,9 +2239,9 @@
"message": "Одбијен приступ. Немате дозволу да видите ову страницу."
},
"general": {
"message": "General"
"message": "Опште"
},
"display": {
"message": "Display"
"message": "Приказ"
}
}

View File

@@ -675,7 +675,7 @@
"message": "Підтвердити експорт сховища"
},
"exportWarningDesc": {
"message": "Експортовані дані вашого сховища знаходяться в незашифрованому вигляді. Вам не слід зберігати чи надсилати їх через незахищені канали (наприклад, е-поштою). Після використання негайно видаліть їх."
"message": "Ваші експортовані дані сховища незашифровані. Не зберігайте і не надсилайте їх незахищеними каналами (як-от електронна пошта). Після використання негайно видаліть їх."
},
"encExportKeyWarningDesc": {
"message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, необхідно виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту."
@@ -2239,9 +2239,9 @@
"message": "Доступ заборонено. У вас немає дозволу на перегляд цієї сторінки."
},
"general": {
"message": "General"
"message": "Загальні"
},
"display": {
"message": "Display"
"message": "Екран"
}
}

View File

@@ -946,7 +946,7 @@
"message": "自定义环境"
},
"customEnvironmentFooter": {
"message": "适用于高级用户。可以分别指定各个服务的基础 URL。"
"message": "适用于高级用户。可以分别指定各个服务的基础 URL。"
},
"baseUrl": {
"message": "服务器 URL"
@@ -2123,7 +2123,7 @@
"message": "设备登录"
},
"loginWithDeviceEnabledInfo": {
"message": "必须在 Bitwarden 应用程序的设置中启用设备登录。需要其他选项吗?"
"message": "设备登录必须在 Bitwarden 应用程序的设置中启用。需要其他选项吗?"
},
"fingerprintPhraseHeader": {
"message": "指纹短语"

View File

@@ -751,8 +751,8 @@
].join('\n\n');
if (
// At least one of the `savedURLs` uses SSL
savedURLs.some(url => url.startsWith('https://')) &&
// At least one of the `savedURLs` uses SSL for the current page
savedURLs.some(url => url.startsWith(`https://${window.location.hostname}`)) &&
// The current page is not using SSL
document.location.protocol === 'http:' &&
// There are password inputs on the page

View File

@@ -409,13 +409,6 @@ export default class AutofillService implements AutofillServiceInterface {
continue;
}
const passwordFieldsForForm: AutofillField[] = [];
passwordFields.forEach((passField) => {
if (formKey === passField.form) {
passwordFieldsForForm.push(passField);
}
});
passwordFields.forEach((passField) => {
pf = passField;
passwords.push(pf);
@@ -438,7 +431,7 @@ export default class AutofillService implements AutofillServiceInterface {
if (!totp && !options.onlyVisibleFields) {
// not able to find any viewable totp fields. maybe there are some "hidden" ones?
totp = this.findTotpField(pageDetails, pf, true, true, true);
totp = this.findTotpField(pageDetails, pf, true, true, false);
}
if (totp) {
@@ -741,6 +734,15 @@ export default class AutofillService implements AutofillServiceInterface {
let exp: string = null;
for (let i = 0; i < CreditCardAutoFillConstants.MonthAbbr.length; i++) {
if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.MonthAbbr[i] +
"/" +
CreditCardAutoFillConstants.YearAbbrLong[i]
)
) {
exp = fullMonth + "/" + fullYear;
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.MonthAbbr[i] +
@@ -753,12 +755,12 @@ export default class AutofillService implements AutofillServiceInterface {
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.MonthAbbr[i] +
CreditCardAutoFillConstants.YearAbbrLong[i] +
"/" +
CreditCardAutoFillConstants.YearAbbrLong[i]
CreditCardAutoFillConstants.MonthAbbr[i]
)
) {
exp = fullMonth + "/" + fullYear;
exp = fullYear + "/" + fullMonth;
} else if (
this.fieldAttrsContain(
fillFields.exp,
@@ -772,12 +774,12 @@ export default class AutofillService implements AutofillServiceInterface {
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.YearAbbrLong[i] +
"/" +
CreditCardAutoFillConstants.MonthAbbr[i]
CreditCardAutoFillConstants.MonthAbbr[i] +
"-" +
CreditCardAutoFillConstants.YearAbbrLong[i]
)
) {
exp = fullYear + "/" + fullMonth;
exp = fullMonth + "-" + fullYear;
} else if (
this.fieldAttrsContain(
fillFields.exp,
@@ -791,12 +793,12 @@ export default class AutofillService implements AutofillServiceInterface {
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.MonthAbbr[i] +
CreditCardAutoFillConstants.YearAbbrLong[i] +
"-" +
CreditCardAutoFillConstants.YearAbbrLong[i]
CreditCardAutoFillConstants.MonthAbbr[i]
)
) {
exp = fullMonth + "-" + fullYear;
exp = fullYear + "-" + fullMonth;
} else if (
this.fieldAttrsContain(
fillFields.exp,
@@ -810,12 +812,10 @@ export default class AutofillService implements AutofillServiceInterface {
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.YearAbbrLong[i] +
"-" +
CreditCardAutoFillConstants.MonthAbbr[i]
CreditCardAutoFillConstants.YearAbbrLong[i] + CreditCardAutoFillConstants.MonthAbbr[i]
)
) {
exp = fullYear + "-" + fullMonth;
exp = fullYear + fullMonth;
} else if (
this.fieldAttrsContain(
fillFields.exp,
@@ -827,10 +827,10 @@ export default class AutofillService implements AutofillServiceInterface {
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.YearAbbrLong[i] + CreditCardAutoFillConstants.MonthAbbr[i]
CreditCardAutoFillConstants.MonthAbbr[i] + CreditCardAutoFillConstants.YearAbbrLong[i]
)
) {
exp = fullYear + fullMonth;
exp = fullMonth + fullYear;
} else if (
this.fieldAttrsContain(
fillFields.exp,
@@ -839,13 +839,6 @@ export default class AutofillService implements AutofillServiceInterface {
partYear != null
) {
exp = fullMonth + partYear;
} else if (
this.fieldAttrsContain(
fillFields.exp,
CreditCardAutoFillConstants.MonthAbbr[i] + CreditCardAutoFillConstants.YearAbbrLong[i]
)
) {
exp = fullMonth + fullYear;
}
if (exp != null) {
@@ -1340,7 +1333,8 @@ export default class AutofillService implements AutofillServiceInterface {
(canBeReadOnly || !f.readonly) &&
(withoutForm || f.form === passwordField.form) &&
(canBeHidden || f.viewable) &&
(f.type === "text" || f.type === "number")
(f.type === "text" || f.type === "number") &&
AutofillService.fieldIsFuzzyMatch(f, AutoFillConstants.TotpFieldNames)
) {
totpField = f;
@@ -1516,7 +1510,7 @@ export default class AutofillService implements AutofillServiceInterface {
}
static hasValue(str: string): boolean {
return str && str !== "";
return Boolean(str && str !== "");
}
static setFillScriptForFocus(

View File

@@ -676,6 +676,9 @@ export default class MainBackground {
return new Promise<void>((resolve) => {
setTimeout(async () => {
await this.environmentService.setUrlsFromStorage();
// Workaround to ignore stateService.activeAccount until URLs are set
// TODO: Remove this when implementing ticket PM-2637
this.environmentService.initialized = true;
if (!this.isPrivateMode) {
await this.refreshBadge();
}

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_extName__",
"short_name": "__MSG_appName__",
"version": "2023.7.0",
"version": "2023.7.1",
"description": "__MSG_extDesc__",
"default_locale": "en",
"author": "Bitwarden Inc.",

View File

@@ -3,7 +3,7 @@
"minimum_chrome_version": "102.0",
"name": "__MSG_extName__",
"short_name": "__MSG_appName__",
"version": "2023.7.0",
"version": "2023.7.1",
"description": "__MSG_extDesc__",
"default_locale": "en",
"author": "Bitwarden Inc.",

View File

@@ -4,6 +4,7 @@ import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import BrowserPlatformUtilsService from "../platform/services/browser-platform-utils.service";
require("./scss/popup.scss");
require("./scss/tailwind.css");
import { AppModule } from "./app.module";

View File

@@ -0,0 +1,5 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "../../../../../libs/components/src/tw-theme.css";

View File

@@ -30,7 +30,11 @@ export class PremiumComponent extends BasePremiumComponent {
// Support old price string. Can be removed in future once all translations are properly updated.
const thePrice = this.currencyPipe.transform(this.price, "$");
this.priceString = i18nService.t("premiumPrice", thePrice);
// Safari extension crashes due to $1 appearing in the price string ($10.00). Escape the $ to fix.
const formattedPrice = this.platformUtilsService.isSafari()
? thePrice.replace("$", "$$$")
: thePrice;
this.priceString = i18nService.t("premiumPrice", formattedPrice);
if (this.priceString.indexOf("%price%") > -1) {
this.priceString = this.priceString.replace("%price%", thePrice);
}

View File

@@ -19,7 +19,11 @@
{{ "passwordGeneratorPolicyInEffect" | i18n }}
</app-callout>
<div class="generated-block" *ngIf="type === 'password'">
<div class="generated-wrapper" [innerHTML]="password | colorPassword" appSelectCopy></div>
<div
class="generated-wrapper"
[innerHTML]="password | colorPassword"
[appCopyText]="password"
></div>
<div class="action-buttons">
<button
type="button"
@@ -41,7 +45,11 @@
</div>
</div>
<div class="generated-block" *ngIf="type === 'username'">
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
<div
class="generated-wrapper"
[innerHTML]="username | colorPassword"
[appCopyText]="username"
></div>
<div class="action-buttons" #form [appApiAction]="usernameGeneratingPromise">
<button
type="button"

View File

@@ -22,7 +22,7 @@
<div class="row-main-content">
<div
class="monospaced password-wrapper"
appSelectCopy
[appCopyText]="h.password"
[innerHTML]="h.password | colorPassword"
></div>
<span class="detail">{{ h.date | date : "medium" }}</span>

View File

@@ -62,7 +62,7 @@ export class VaultSelectComponent implements OnInit, OnDestroy {
selectedVault$: Observable<string | null> = this._selectedVault.asObservable();
enforcePersonalOwnership = false;
overlayPostition: ConnectedPosition[] = [
overlayPosition: ConnectedPosition[] = [
{
originX: "start",
originY: "bottom",
@@ -149,7 +149,7 @@ export class VaultSelectComponent implements OnInit, OnDestroy {
.withPush(true)
.withViewportMargin(10)
.withGrowAfterOpen(true)
.withPositions(this.overlayPostition);
.withPositions(this.overlayPosition);
this.overlayRef = this.overlay.create({
hasBackdrop: true,

View File

@@ -72,7 +72,7 @@
<div
*ngIf="showPassword && !showPasswordCount"
class="monospaced password-wrapper"
appSelectCopy
[appCopyText]="cipher.login.password"
[innerHTML]="cipher.login.password | colorPassword"
></div>
<div

View File

@@ -118,10 +118,10 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Free Password Manager</value>
<value>Bitwarden - Rheolydd cyfineiriau am ddim</value>
</data>
<data name="Summary" xml:space="preserve">
<value>A secure and free password manager for all of your devices</value>
<value>Rheolydd diogel a rhad ac am ddim ar gyfer eich holl ddyfeisiau</value>
</data>
<data name="Description" xml:space="preserve">
<value>Bitwarden, Inc. is the parent company of 8bit Solutions LLC.
@@ -152,7 +152,7 @@ Secure and share sensitive data within your Bitwarden Vault from any browser, mo
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>A secure and free password manager for all of your devices</value>
<value>Rheolydd diogel a rhad ac am ddim ar gyfer eich holl ddyfeisiau</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Sync and access your vault from multiple devices</value>
@@ -170,6 +170,6 @@ Secure and share sensitive data within your Bitwarden Vault from any browser, mo
<value>Automatically generate strong, random, and secure passwords</value>
</data>
<data name="ScreenshotEdit" xml:space="preserve">
<value>Your information is managed securely using AES-256 bit encryption</value>
<value>Mae eich gwybodaeth yn cael ei reoli'n ddiogel gan ddefnyddio manyleb amgryptio AES 256 did</value>
</data>
</root>

View File

@@ -124,19 +124,19 @@
<value>Saugi ir nemokama slaptažodžių tvarkyklė visiems įrenginiams</value>
</data>
<data name="Description" xml:space="preserve">
<value>Bitwarden, Inc. yra pagrindinė 8bit Solutions LLC įmonė.
<value>Bitwarden, Inc. yra pagrindinė 8bit Solutions LLC įmonė.
ĮVARDINTA GERIAUSIU SLAPTAŽODŽIŲ TVARKYTOJU.
Tvarkykite, saugokite, saugokite ir bendrinkite neribotą skaičių slaptažodžių neribotuose įrenginiuose iš bet kurios vietos. Bitwarden teikia atvirojo kodo slaptažodžių valdymo sprendimus visiems tiek namuose, tiek darbe, tiek keliaujant.
Tvarkykite, saugokite, saugokite ir bendrinkite neribotą skaičių slaptažodžių neribotuose įrenginiuose iš bet kurios vietos. Bitwarden teikia atvirojo kodo slaptažodžių valdymo sprendimus visiems tiek namuose, tiek darbe, tiek keliaujant.
Generuokite stiprius, unikalius ir atsitiktinius slaptažodžius pagal saugos reikalavimus kiekvienai lankomai svetainei.
Bitwarden Send greitai perduoda užšifruotą informaciją failus ir paprastą tekstą tiesiogiai bet kam.
Bitwarden Send greitai perduoda užšifruotą informaciją failus ir paprastą tekstą tiesiogiai bet kam.
Bitwarden siūlo komandų ir įmonių planus įmonėms, kad galėtumėte saugiai dalytis slaptažodžiais su kolegomis.
Kodėl verta rinktis Bitwarden:
Kodėl rinktis Bitwarden:
Pasaulinės klasės šifravimas
Slaptažodžiai yra apsaugoti naudojant pažangų šifravimą nuo galo iki galo (AES-256 bitai, žyma su grotelėmis ir PBKDF2 SHA-256), todėl jūsų duomenys išliks saugūs ir privatūs.
@@ -145,10 +145,10 @@ Integruotas slaptažodžių generatorius
Generuokite stiprius, unikalius ir atsitiktinius slaptažodžius pagal saugos reikalavimus kiekvienai lankomai svetainei.
Pasauliniai vertimai
Bitwarden vertimai egzistuoja 40 kalbų ir mūsų pasaulinės bendruomenės dėka auga.
Bitwarden vertimai egzistuoja 40 kalbose ir vis daugėja mūsų pasaulinės bendruomenės dėka.
Įvairių platformų programos
Apsaugokite ir bendrinkite neskelbtinus duomenis savo Bitwarden Vault iš bet kurios naršyklės, mobiliojo įrenginio ar stalinio kompiuterio OS ir kt.
Apsaugokite ir bendrinkite neskelbtinus duomenis savo Bitwarden Vault iš bet kurios naršyklės, mobiliojo įrenginio ar stalinio kompiuterio OS ir kt.
</value>
</data>
<data name="AssetTitle" xml:space="preserve">

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Free Password Manager</value>
</data>
<data name="Summary" xml:space="preserve">
<value>A secure and free password manager for all of your devices</value>
</data>
<data name="Description" xml:space="preserve">
<value>Bitwarden, Inc. is the parent company of 8bit Solutions LLC.
NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS &amp; WORLD REPORT, CNET, AND MORE.
Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go.
Generate strong, unique, and random passwords based on security requirements for every website you frequent.
Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone.
Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues.
Why Choose Bitwarden:
World-Class Encryption
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private.
Built-in Password Generator
Generate strong, unique, and random passwords based on security requirements for every website you frequent.
Global Translations
Bitwarden translations exist in 40 languages and are growing, thanks to our global community.
Cross-Platform Applications
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>A secure and free password manager for all of your devices</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Sync and access your vault from multiple devices</value>
</data>
<data name="ScreenshotVault" xml:space="preserve">
<value>Manage all your logins and passwords from a secure vault</value>
</data>
<data name="ScreenshotAutofill" xml:space="preserve">
<value>Quickly auto-fill your login credentials into any website that you visit</value>
</data>
<data name="ScreenshotMenu" xml:space="preserve">
<value>Your vault is also conveniently accessible from the right-click menu</value>
</data>
<data name="ScreenshotPassword" xml:space="preserve">
<value>Automatically generate strong, random, and secure passwords</value>
</data>
<data name="ScreenshotEdit" xml:space="preserve">
<value>Your information is managed securely using AES-256 bit encryption</value>
</data>
</root>

View File

@@ -0,0 +1,6 @@
/* eslint-disable no-undef, @typescript-eslint/no-var-requires */
const config = require("../../libs/components/tailwind.config.base");
config.content = ["./src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}"];
module.exports = config;

View File

@@ -10,8 +10,9 @@
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@bitwarden/common/*": ["../../libs/common/src/*"],
"@bitwarden/angular/*": ["../../libs/angular/src/*"],
"@bitwarden/common/*": ["../../libs/common/src/*"],
"@bitwarden/components": ["../../libs/components/src"],
"@bitwarden/exporter/*": ["../../libs/exporter/src/*"]
},
"useDefineForClassFields": false

View File

@@ -42,6 +42,16 @@ const moduleRules = [
},
type: "asset/resource",
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
"postcss-loader",
],
},
{
test: /\.scss$/,
use: [

View File

@@ -1,7 +1,7 @@
{
"name": "@bitwarden/desktop",
"description": "A secure and free password manager for all of your devices.",
"version": "2023.7.0",
"version": "2023.7.1",
"keywords": [
"bitwarden",
"password",

View File

@@ -0,0 +1,4 @@
/* eslint-disable no-undef */
module.exports = {
plugins: [require("tailwindcss"), require("autoprefixer"), require("postcss-nested")],
};

View File

@@ -10,6 +10,7 @@ import {
} from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import { Router } from "@angular/router";
import { ipcRenderer } from "electron";
import { IndividualConfig, ToastrService } from "ngx-toastr";
import { firstValueFrom, Subject, takeUntil } from "rxjs";
@@ -221,7 +222,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.systemService.cancelProcessReload();
break;
case "reloadProcess":
(window.location as any).reload(true);
ipcRenderer.send("reload-process");
break;
case "syncStarted":
break;

View File

@@ -42,7 +42,7 @@
(backdropClick)="close()"
(detach)="close()"
[cdkConnectedOverlayOpen]="showSwitcher && isOpen"
[cdkConnectedOverlayPositions]="overlayPostition"
[cdkConnectedOverlayPositions]="overlayPosition"
cdkConnectedOverlayMinWidth="250px"
>
<div

View File

@@ -68,7 +68,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
activeAccount?: ActiveAccount;
serverUrl: string;
authStatus = AuthenticationStatus;
overlayPostition: ConnectedPosition[] = [
overlayPosition: ConnectedPosition[] = [
{
originX: "end",
originY: "bottom",

View File

@@ -3,8 +3,8 @@ import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { isDev } from "../utils";
// tslint:disable-next-line
require("../scss/styles.scss");
require("../scss/tailwind.css");
import { AppModule } from "./app.module";

View File

@@ -44,6 +44,9 @@ export class InitService {
this.nativeMessagingService.init();
await this.stateService.init();
await this.environmentService.setUrlsFromStorage();
// Workaround to ignore stateService.activeAccount until URLs are set
// TODO: Remove this when implementing ticket PM-2637
this.environmentService.initialized = true;
this.syncService.fullSync(true);
(this.vaultTimeoutService as VaultTimeoutService).init(true);
const locale = await this.stateService.getLocale();

View File

@@ -12,7 +12,11 @@
{{ "passwordGeneratorPolicyInEffect" | i18n }}
</app-callout>
<div class="generated-block" *ngIf="type === 'password'">
<div class="generated-wrapper" [innerHTML]="password | colorPassword" appSelectCopy></div>
<div
class="generated-wrapper"
[innerHTML]="password | colorPassword"
[appCopyText]="password"
></div>
<div class="action-buttons">
<button
type="button"
@@ -35,7 +39,11 @@
</div>
</div>
<div class="generated-block" *ngIf="type === 'username'">
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
<div
class="generated-wrapper"
[innerHTML]="username | colorPassword"
[appCopyText]="username"
></div>
<div class="action-buttons" #form [appApiAction]="usernameGeneratingPromise">
<button
type="button"

View File

@@ -11,7 +11,7 @@
<div class="row-main">
<div
class="password-wrapper monospaced"
appSelectCopy
[appCopyText]="h.password"
[innerHTML]="h.password | colorPassword"
></div>
<span class="detail">{{ h.date | date : "medium" }}</span>

View File

@@ -2267,6 +2267,6 @@
"message": "Selghehuisves"
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
"message": "Toegang geweier. U het nie toestemming om hierdie blad te sien nie."
}
}

View File

@@ -567,7 +567,7 @@
"message": "Kohteen tiedot"
},
"noItemsInList": {
"message": "Ei näytettäviä kohteita."
"message": "Näytettäviä kohteita ei ole."
},
"sendVerificationCode": {
"message": "Lähetä todennuskoodi sähköpostiisi"
@@ -2125,7 +2125,7 @@
"message": "Tunnistelauseke"
},
"needAnotherOption": {
"message": "Laitteella kirjautuminen on määritettävä Bitwarden-mobiilisovelluksen asetuksista. Tarvitsetko eri vaihtoehdon?"
"message": "Laitteella kirjautuminen on määritettävä Bitwarden-sovelluksen asetuksista. Tarvitsetko eri vaihtoehdon?"
},
"viewAllLoginOptions": {
"message": "Näytä kaikki kirjautumisvaihtoehdot"

File diff suppressed because it is too large Load Diff

View File

@@ -1335,7 +1335,7 @@
"message": "Підтвердити експорт сховища"
},
"exportWarningDesc": {
"message": "Експортовані дані вашого сховища знаходяться в незашифрованому вигляді. Вам не слід зберігати чи надсилати їх через незахищені канали (наприклад, е-поштою). Після використання негайно видаліть їх."
"message": "Ваші експортовані дані сховища незашифровані. Не зберігайте і не надсилайте їх незахищеними каналами (як-от електронна пошта). Після використання негайно видаліть їх."
},
"encExportKeyWarningDesc": {
"message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, необхідно виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту."

View File

@@ -690,7 +690,7 @@
"message": "自定义环境"
},
"customEnvironmentFooter": {
"message": "适用于高级用户。可以分别指定各个服务的基础 URL。"
"message": "适用于高级用户。可以分别指定各个服务的基础 URL。"
},
"baseUrl": {
"message": "服务器 URL"
@@ -2125,7 +2125,7 @@
"message": "指纹短语"
},
"needAnotherOption": {
"message": "必须在 Bitwarden 应用程序的设置中启用设备登录。需要其他选项吗?"
"message": "设备登录必须在 Bitwarden 应用程序的设置中启用。需要其他选项吗?"
},
"viewAllLoginOptions": {
"message": "查看所有登录选项"

View File

@@ -98,6 +98,7 @@ export class Main {
this.windowMain = new WindowMain(
this.stateService,
this.logService,
this.storageService,
(arg) => this.processDeepLink(arg),
(win) => this.trayMain.setupWindowListeners(win)
);

View File

@@ -1,11 +1,13 @@
import { once } from "node:events";
import * as path from "path";
import * as url from "url";
import { app, BrowserWindow, screen } from "electron";
import { app, BrowserWindow, ipcMain, nativeTheme, screen, session } from "electron";
import { WindowState } from "@bitwarden/common/models/domain/window-state";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { cleanUserAgent, isDev, isMacAppStore, isSnapStore } from "../utils";
@@ -19,6 +21,7 @@ export class WindowMain {
private windowStateChangeTimer: NodeJS.Timer;
private windowStates: { [key: string]: WindowState } = {};
private enableAlwaysOnTop = false;
private session: Electron.Session;
readonly defaultWidth = 950;
readonly defaultHeight = 600;
@@ -26,11 +29,26 @@ export class WindowMain {
constructor(
private stateService: StateService,
private logService: LogService,
private storageService: AbstractStorageService,
private argvCallback: (argv: string[]) => void = null,
private createWindowCallback: (win: BrowserWindow) => void
) {}
init(): Promise<any> {
// Perform a hard reload of the render process by crashing it. This is suboptimal but ensures that all memory gets
// cleared, as the process itself will be completely garbage collected.
ipcMain.on("reload-process", async () => {
// User might have changed theme, ensure the window is updated.
this.win.setBackgroundColor(await this.getBackgroundColor());
const crashEvent = once(this.win.webContents, "render-process-gone");
this.win.webContents.forcefullyCrashRenderer();
await crashEvent;
this.win.webContents.reloadIgnoringCache();
this.session.clearCache();
});
return new Promise<void>((resolve, reject) => {
try {
if (!isMacAppStore() && !isSnapStore()) {
@@ -108,6 +126,8 @@ export class WindowMain {
);
this.enableAlwaysOnTop = await this.stateService.getEnableAlwaysOnTop();
this.session = session.fromPartition("persist:bitwarden", { cache: false });
// Create the browser window.
this.win = new BrowserWindow({
width: this.windowStates[mainWindowSizeKey].width,
@@ -120,13 +140,14 @@ export class WindowMain {
icon: process.platform === "linux" ? path.join(__dirname, "/images/icon.png") : undefined,
titleBarStyle: process.platform === "darwin" ? "hiddenInset" : undefined,
show: false,
backgroundColor: "#fff",
backgroundColor: await this.getBackgroundColor(),
alwaysOnTop: this.enableAlwaysOnTop,
webPreferences: {
spellcheck: false,
nodeIntegration: true,
backgroundThrottling: false,
contextIsolation: false,
session: this.session,
},
});
@@ -201,6 +222,26 @@ export class WindowMain {
}
}
// Retrieve the background color
// Resolves background color missmatch when starting the application.
async getBackgroundColor(): Promise<string> {
const data: { theme?: string } = await this.storageService.get("global");
let theme = data?.theme;
if (theme == null || theme === "system") {
theme = nativeTheme.shouldUseDarkColors ? "dark" : "light";
}
switch (theme) {
case "light":
return "#ededed";
case "dark":
return "#222222";
case "nord":
return "#3b4252";
}
}
async toggleAlwaysOnTop() {
this.enableAlwaysOnTop = !this.win.isAlwaysOnTop();
this.win.setAlwaysOnTop(this.enableAlwaysOnTop);

View File

@@ -1,12 +1,12 @@
{
"name": "@bitwarden/desktop",
"version": "2023.7.0",
"version": "2023.7.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@bitwarden/desktop",
"version": "2023.7.0",
"version": "2023.7.1",
"license": "GPL-3.0",
"dependencies": {
"@bitwarden/desktop-native": "file:../desktop_native"

View File

@@ -2,7 +2,7 @@
"name": "@bitwarden/desktop",
"productName": "Bitwarden",
"description": "A secure and free password manager for all of your devices.",
"version": "2023.7.0",
"version": "2023.7.1",
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
"homepage": "https://bitwarden.com",
"license": "GPL-3.0",

View File

@@ -16,7 +16,10 @@ body {
body {
color: $text-color;
background-color: $background-color-alt2;
// We initially rely on electron to provide the appropiate background color.
// This ensures the background color while reloading is correct to avoid a jarring missmatch.
background-color: transparent;
@include themify($themes) {
color: themed("textColor");

View File

@@ -0,0 +1,5 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "../../../../libs/components/src/tw-theme.css";

View File

@@ -28,7 +28,7 @@ $brand-primary-accent: #1252a3;
$background-color: white;
$background-color-alt: #f9f9f9;
$background-color-alt2: #ededed;
$background-color-alt2: #ededed; // Ensure the `window.main.ts` is updated with this value
$box-background-color: $background-color;
$box-background-hover-color: $list-item-hover;
@@ -50,6 +50,7 @@ $themes: (
backgroundColor: $background-color,
borderColorAlt: $border-color-alt,
backgroundColorAlt: $background-color-alt,
// Ensure the `window.main.ts` is updated with this value
backgroundColorAlt2: $background-color-alt2,
scrollbarColor: rgba(100, 100, 100, 0.2),
scrollbarHoverColor: rgba(100, 100, 100, 0.4),
@@ -107,6 +108,7 @@ $themes: (
backgroundColor: #363636,
borderColorAlt: #6e788a,
backgroundColorAlt: #3d3d3d,
// Ensure the `window.main.ts` is updated with this value
backgroundColorAlt2: #222222,
scrollbarColor: #4d4d4d,
scrollbarHoverColor: #5f5f5f,
@@ -164,6 +166,7 @@ $themes: (
backgroundColor: $nord2,
borderColorAlt: $nord5,
backgroundColorAlt: $nord1,
// Ensure the `window.main.ts` is updated with this value
backgroundColorAlt2: $nord1,
scrollbarColor: $nord4,
scrollbarHoverColor: $nord6,

View File

@@ -52,7 +52,7 @@
<div
*ngIf="showPassword && !showPasswordCount"
class="monospaced password-wrapper"
appSelectCopy
[appCopyText]="cipher.login.password"
[innerHTML]="cipher.login.password | colorPassword"
></div>
<div

View File

@@ -0,0 +1,6 @@
/* eslint-disable no-undef, @typescript-eslint/no-var-requires */
const config = require("../../libs/components/tailwind.config.base");
config.content = ["./src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}"];
module.exports = config;

View File

@@ -10,8 +10,9 @@
"types": [],
"baseUrl": ".",
"paths": {
"@bitwarden/common/*": ["../../libs/common/src/*"],
"@bitwarden/angular/*": ["../../libs/angular/src/*"],
"@bitwarden/common/*": ["../../libs/common/src/*"],
"@bitwarden/components": ["../../libs/components/src"],
"@bitwarden/exporter/*": ["../../libs/exporter/src/*"]
},
"useDefineForClassFields": false

View File

@@ -109,6 +109,16 @@ const renderer = {
},
type: "asset/resource",
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
"postcss-loader",
],
},
{
test: /\.scss$/,
use: [

View File

@@ -4,6 +4,12 @@
"notifications": "https://notifications.bitwarden.eu",
"scim": "https://scim.bitwarden.eu"
},
"stripeKey": "pk_live_bpN0P37nMxrMQkcaHXtAybJk",
"braintreeKey": "production_qfbsv8kc_njj2zjtyngtjmbjd",
"paypal": {
"businessId": "4ZDA7DLUUJGMN",
"buttonAction": "https://www.paypal.com/cgi-bin/webscr"
},
"flags": {
"secretsManager": true,
"showPasswordless": true

View File

@@ -1,40 +1,23 @@
<app-callout type="info" *ngIf="showKeyConnectorInfo">
<bit-callout type="info" *ngIf="showKeyConnectorInfo">
{{ "keyConnectorPolicyRestriction" | i18n }}
</app-callout>
</bit-callout>
<app-callout type="warning">
{{ "resetPasswordPolicyWarning" | i18n }}
</app-callout>
<bit-callout type="success" [title]="'prerequisite' | i18n" icon="bwi-lightbulb">
{{ "accountRecoverySingleOrgRequirementDesc" | i18n }}
</bit-callout>
<div class="form-group">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
id="enabled"
[formControl]="enabled"
name="Enabled"
/>
<label class="form-check-label" for="enabled">{{ "turnOn" | i18n }}</label>
</div>
</div>
<bit-callout type="warning">
{{ "accountRecoveryPolicyWarning" | i18n }}
</bit-callout>
<div [formGroup]="data">
<h3 class="mt-4">{{ "resetPasswordPolicyAutoEnroll" | i18n }}</h3>
<p>{{ "resetPasswordPolicyAutoEnrollDescription" | i18n }}</p>
<app-callout type="warning">
{{ "resetPasswordPolicyAutoEnrollWarning" | i18n }}
</app-callout>
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
id="autoEnrollEnabled"
name="AutoEnrollEnabled"
formControlName="autoEnrollEnabled"
/>
<label class="form-check-label" for="autoEnrollEnabled">
{{ "resetPasswordPolicyAutoEnrollCheckbox" | i18n }}
</label>
</div>
</div>
<bit-form-control class="!tw-mb-1">
<input type="checkbox" bitCheckbox [formControl]="enabled" id="enabled" />
<bit-label>{{ "turnOn" | i18n }}</bit-label>
</bit-form-control>
<ng-container [formGroup]="data">
<bit-form-control class="!tw-mb-1">
<input type="checkbox" bitCheckbox formControlName="autoEnrollEnabled" id="autoEnrollEnabled" />
<bit-label>{{ "resetPasswordPolicyAutoEnrollCheckbox" | i18n }}</bit-label>
</bit-form-control>
</ng-container>

View File

@@ -1,5 +1,5 @@
import { Component } from "@angular/core";
import { UntypedFormBuilder } from "@angular/forms";
import { FormBuilder } from "@angular/forms";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
@@ -9,7 +9,7 @@ import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
export class ResetPasswordPolicy extends BasePolicy {
name = "accountRecoveryPolicy";
description = "accountRecoveryPolicyDescription";
description = "accountRecoveryPolicyDesc";
type = PolicyType.ResetPassword;
component = ResetPasswordPolicyComponent;
@@ -26,14 +26,9 @@ export class ResetPasswordPolicyComponent extends BasePolicyComponent {
data = this.formBuilder.group({
autoEnrollEnabled: false,
});
defaultTypes: { name: string; value: string }[];
showKeyConnectorInfo = false;
constructor(
private formBuilder: UntypedFormBuilder,
private organizationService: OrganizationService
) {
constructor(private formBuilder: FormBuilder, private organizationService: OrganizationService) {
super();
}

View File

@@ -51,7 +51,7 @@ describe("TrialInitiationComponent", () => {
component: BlankComponent,
},
{
path: `organizations/${testOrgId}/manage/members`,
path: `organizations/${testOrgId}/members`,
component: BlankComponent,
},
]),
@@ -301,7 +301,7 @@ describe("TrialInitiationComponent", () => {
describe("navigateToOrgVault", () => {
it("should call verticalStepper.previous()", fakeAsync(() => {
component.navigateToOrgInvite();
expect(routerSpy).toHaveBeenCalledWith(["organizations", testOrgId, "manage", "members"]);
expect(routerSpy).toHaveBeenCalledWith(["organizations", testOrgId, "members"]);
}));
});
});

View File

@@ -227,7 +227,7 @@ export class TrialInitiationComponent implements OnInit, OnDestroy {
}
navigateToOrgInvite() {
this.router.navigate(["organizations", this.orgId, "manage", "members"]);
this.router.navigate(["organizations", this.orgId, "members"]);
}
previousStep() {

View File

@@ -1,18 +1,7 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { UntypedFormBuilder, FormGroup } from "@angular/forms";
import { Router } from "@angular/router";
import { FormGroup } from "@angular/forms";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { ProductType } from "@bitwarden/common/enums";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { OrganizationPlansComponent } from "../../settings/organization-plans.component";
@@ -24,36 +13,6 @@ export class BillingComponent extends OrganizationPlansComponent {
@Input() orgInfoForm: FormGroup;
@Output() previousStep = new EventEmitter();
constructor(
apiService: ApiService,
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
cryptoService: CryptoService,
router: Router,
syncService: SyncService,
policyService: PolicyService,
organizationService: OrganizationService,
logService: LogService,
messagingService: MessagingService,
formBuilder: UntypedFormBuilder,
organizationApiService: OrganizationApiServiceAbstraction
) {
super(
apiService,
i18nService,
platformUtilsService,
cryptoService,
router,
syncService,
policyService,
organizationService,
logService,
messagingService,
formBuilder,
organizationApiService
);
}
async ngOnInit() {
const additionalSeats = this.product == ProductType.Families ? 0 : 1;
this.formGroup.patchValue({

View File

@@ -1,7 +1,7 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
<div>
<div class="row">
<div class="form-group col-6">
<div class="form-group col-8">
<label for="newSeatCount">{{ "subscriptionSeats" | i18n }}</label>
<input
id="newSeatCount"
@@ -41,7 +41,7 @@
<label for="maxAutoscaleSeats">{{ "maxSeatLimit" | i18n }}</label>
<input
id="maxAutoscaleSeats"
class="form-control col-6"
class="form-control col-8"
type="number"
name="MaxAutoscaleSeats"
[(ngModel)]="newMaxSeats"

View File

@@ -40,7 +40,7 @@ export class AdjustSubscription {
try {
const seatAdjustment = this.newSeatCount - this.currentSeatCount;
const request = new OrganizationSubscriptionUpdateRequest(seatAdjustment, this.newMaxSeats);
this.formPromise = this.organizationApiService.updateSubscription(
this.formPromise = this.organizationApiService.updatePasswordManagerSeats(
this.organizationId,
request
);

View File

@@ -12,7 +12,7 @@ import { OrganizationBillingRoutingModule } from "./organization-billing-routing
import { OrganizationBillingTabComponent } from "./organization-billing-tab.component";
import { OrganizationSubscriptionCloudComponent } from "./organization-subscription-cloud.component";
import { OrganizationSubscriptionSelfhostComponent } from "./organization-subscription-selfhost.component";
import { SecretsManagerEnrollComponent } from "./secrets-manager/enroll.component";
import { SecretsManagerBillingModule } from "./secrets-manager/sm-billing.module";
import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
@NgModule({
@@ -21,6 +21,7 @@ import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
LooseComponentsModule,
OrganizationBillingRoutingModule,
UserVerificationModule,
SecretsManagerBillingModule,
],
declarations: [
AdjustSubscription,
@@ -32,7 +33,6 @@ import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
OrganizationSubscriptionSelfhostComponent,
OrganizationSubscriptionCloudComponent,
SubscriptionHiddenComponent,
SecretsManagerEnrollComponent,
],
})
export class OrganizationBillingModule {}

View File

@@ -1,5 +1,5 @@
<div class="page-header">
<h1>
<div class="tw-mb-2">
<h1 bitTypography="h1">
{{ "subscription" | i18n }}
<small *ngIf="firstLoaded && loading">
<i
@@ -7,7 +7,7 @@
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
<span class="sr-only">{{ "loading" | i18n }}</span>
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
</small>
</h1>
</div>
@@ -21,7 +21,7 @@
[providerName]="userOrg.providerName"
></app-org-subscription-hidden>
<ng-container *ngIf="sub">
<ng-container *ngIf="sub && firstLoaded">
<bit-callout
type="warning"
title="{{ 'canceled' | i18n }}"
@@ -40,15 +40,13 @@
</button>
</bit-callout>
<div class="row">
<div class="col-4">
<dl>
<dl class="tw-grid tw-grid-flow-col tw-grid-rows-2">
<dt>{{ "billingPlan" | i18n }}</dt>
<dd>{{ sub.plan.name }}</dd>
<ng-container *ngIf="subscription">
<dt>{{ "status" | i18n }}</dt>
<dd>
<span class="text-capitalize">{{
<span class="tw-capitalize">{{
isSponsoredSubscription ? "sponsored" : subscription.status || "-"
}}</span>
<span bitBadge badgeType="warning" *ngIf="subscriptionMarkedForCancel">{{
@@ -63,25 +61,44 @@
</dd>
</ng-container>
</dl>
</div>
<ng-container *ngIf="userOrg.canEditSubscription">
<div class="col-8" *ngIf="subscription">
<strong class="d-block mb-1">{{ "details" | i18n }}</strong>
<table class="table">
<tbody>
<tr *ngFor="let i of subscription.items">
<td>
<div class="tw-flex-col">
<strong class="tw-block tw-border-0 tw-border-b tw-border-solid tw-border-secondary-300">{{
"details" | i18n
}}</strong>
<bit-table>
<ng-template body>
<ng-container *ngIf="subscription">
<tr bitRow *ngFor="let i of lineItems">
<td bitCell [ngClass]="{ 'tw-pl-20': i.addonSubscriptionItem }">
<span *ngIf="!i.addonSubscriptionItem"
>{{ productName(i.bitwardenProduct) }} -</span
>
{{ i.name }} {{ i.quantity > 1 ? "&times;" + i.quantity : "" }} @
{{ i.amount | currency : "$" }}
</td>
<td>{{ i.quantity * i.amount | currency : "$" }} /{{ i.interval | i18n }}</td>
<td bitCell class="tw-text-right">
{{ i.quantity * i.amount | currency : "$" }} /{{ i.interval | i18n }}
</td>
</tr>
</tbody>
</table>
</ng-container>
<ng-container *ngIf="userOrg.isFreeOrg">
<tr bitRow *ngIf="userOrg.usePasswordManager">
<td bitCell>{{ "passwordManager" | i18n }} - {{ "freeOrganization" | i18n }}</td>
<td bitCell class="tw-text-right">{{ "free" | i18n }}</td>
</tr>
<tr bitRow *ngIf="userOrg.useSecretsManager">
<td bitCell>{{ "secretsManager" | i18n }} - {{ "freeOrganization" | i18n }}</td>
<td bitCell class="tw-text-right">{{ "free" | i18n }}</td>
</tr>
</ng-container>
</ng-template>
</bit-table>
</div>
</ng-container>
</div>
<ng-container *ngIf="userOrg.canEditSubscription">
<div class="tw-mt-7">
<button
bitButton
buttonType="secondary"
@@ -97,25 +114,28 @@
(onCanceled)="closeChangePlan()"
*ngIf="showChangePlan"
></app-change-plan>
</div>
</ng-container>
<ng-container *ngIf="showSecretsManagerSubscribe">
<div class="tw-mt-7">
<sm-subscribe-standalone
[plan]="sub.secretsManagerPlan"
[organization]="userOrg"
(onSubscribe)="subscriptionAdjusted()"
></sm-subscribe-standalone>
</div>
</ng-container>
<ng-container *ngIf="userOrg.canEditSubscription">
<sm-enroll
*ngIf="isAdmin"
[enabled]="sub?.useSecretsManager"
[organizationId]="organizationId"
></sm-enroll>
</ng-container>
<ng-container *ngIf="userOrg.canEditSubscription">
<h2 class="spaced-header">{{ "manageSubscription" | i18n }}</h2>
<p class="mb-4">{{ subscriptionDesc }}</p>
<h2 bitTypography="h2" class="tw-mt-7">{{ "manageSubscription" | i18n }}</h2>
<p bitTypography="body1">{{ subscriptionDesc }}</p>
<ng-container
*ngIf="
subscription && canAdjustSeats && !subscription.cancelled && !subscriptionMarkedForCancel
"
>
<div class="mt-3">
<h3 bitTypography="h3" class="tw-mt-7">{{ "passwordManager" | i18n }}</h3>
<app-adjust-subscription
[seatPrice]="seatPrice"
[organizationId]="organizationId"
@@ -125,7 +145,6 @@
(onAdjusted)="subscriptionAdjusted()"
>
</app-adjust-subscription>
</div>
</ng-container>
<button
bitButton
@@ -136,33 +155,18 @@
>
{{ "removeSponsorship" | i18n }}
</button>
<h2 class="spaced-header">{{ "storage" | i18n }}</h2>
<p>{{ "subscriptionStorage" | i18n : sub.maxStorageGb || 0 : sub.storageName || "0 MB" }}</p>
<div class="progress">
<div
class="progress-bar bg-success"
role="progressbar"
[ngStyle]="{ width: storageProgressWidth + '%' }"
[attr.aria-valuenow]="storagePercentage"
aria-valuemin="0"
aria-valuemax="100"
>
{{ storagePercentage / 100 | percent }}
</div>
</div>
<h4 bitTypography="h4" class="tw-mt-9">{{ "storage" | i18n }}</h4>
<p bitTypography="body1">
{{ "subscriptionStorage" | i18n : sub.maxStorageGb || 0 : sub.storageName || "0 MB" }}
</p>
<bit-progress [barWidth]="storagePercentage" bgColor="success"></bit-progress>
<ng-container *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel">
<div class="mt-3">
<div class="d-flex" *ngIf="!showAdjustStorage">
<div class="tw-mt-3">
<div class="tw-flex tw-space-x-2" *ngIf="!showAdjustStorage">
<button bitButton buttonType="secondary" type="button" (click)="adjustStorage(true)">
{{ "addStorage" | i18n }}
</button>
<button
bitButton
buttonType="secondary"
type="button"
class="ml-1"
(click)="adjustStorage(false)"
>
<button bitButton buttonType="secondary" type="button" (click)="adjustStorage(false)">
{{ "removeStorage" | i18n }}
</button>
</div>
@@ -177,13 +181,21 @@
></app-adjust-storage>
</div>
</ng-container>
<ng-container *ngIf="showAdjustSecretsManager">
<h3 bitTypography="h3" class="tw-mt-9">{{ "secretsManager" | i18n }}</h3>
<app-sm-adjust-subscription
[organizationId]="organizationId"
[options]="smOptions"
(onAdjusted)="subscriptionAdjusted()"
></app-sm-adjust-subscription>
</ng-container>
</ng-container>
<h2 class="spaced-header">{{ "selfHostingTitle" | i18n }}</h2>
<p class="mb-4">
<h2 bitTypography="h2" class="tw-mt-7">{{ "selfHostingTitle" | i18n }}</h2>
<p bitTypography="body1">
{{ "selfHostingEnterpriseOrganizationSectionCopy" | i18n }}
</p>
<div class="d-flex">
<div class="tw-flex tw-space-x-2">
<button
bitButton
buttonType="secondary"
@@ -198,14 +210,13 @@
bitButton
buttonType="secondary"
type="button"
class="ml-1"
(click)="manageBillingSync()"
*ngIf="canManageBillingSync"
>
{{ (hasBillingSyncToken ? "manageBillingSync" : "setUpBillingSync") | i18n }}
</button>
</div>
<div class="mt-3" *ngIf="showDownloadLicense">
<div class="tw-mt-3" *ngIf="showDownloadLicense">
<app-download-license
[organizationId]="organizationId"
(onDownloaded)="closeDownloadLicense()"
@@ -213,17 +224,16 @@
></app-download-license>
</div>
<ng-container *ngIf="userOrg.canEditSubscription">
<h2 class="spaced-header">{{ "additionalOptions" | i18n }}</h2>
<p class="mb-4">
<h2 bitTypography="h2" class="tw-mt-7">{{ "additionalOptions" | i18n }}</h2>
<p bitTypography="body1">
{{ "additionalOptionsDesc" | i18n }}
</p>
<div class="d-flex">
<div class="tw-flex tw-space-x-2">
<button
bitButton
buttonType="danger"
[bitAction]="cancel"
type="button"
class="ml-1"
*ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"
>
{{ "cancelSubscription" | i18n }}

View File

@@ -9,8 +9,11 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { OrganizationApiKeyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { PlanType } from "@bitwarden/common/billing/enums";
import { BitwardenProductType, PlanType } from "@bitwarden/common/billing/enums";
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
import { BillingSubscriptionItemResponse } from "@bitwarden/common/billing/models/response/subscription.response";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@@ -19,6 +22,7 @@ import {
BillingSyncApiKeyComponent,
BillingSyncApiModalData,
} from "./billing-sync-api-key.component";
import { SecretsManagerSubscriptionOptions } from "./secrets-manager/sm-adjust-subscription.component";
@Component({
selector: "app-org-subscription-cloud",
@@ -26,6 +30,7 @@ import {
})
export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy {
sub: OrganizationSubscriptionResponse;
lineItems: BillingSubscriptionItemResponse[] = [];
organizationId: string;
userOrg: Organization;
showChangePlan = false;
@@ -33,6 +38,9 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
adjustStorageAdd = true;
showAdjustStorage = false;
hasBillingSyncToken: boolean;
showAdjustSecretsManager = false;
showSecretsManagerSubscribe = false;
firstLoaded = false;
loading: boolean;
@@ -48,7 +56,8 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
private organizationService: OrganizationService,
private organizationApiService: OrganizationApiServiceAbstraction,
private route: ActivatedRoute,
private dialogService: DialogServiceAbstraction
private dialogService: DialogServiceAbstraction,
private configService: ConfigServiceAbstraction
) {}
async ngOnInit() {
@@ -68,6 +77,17 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
.subscribe();
}
productName(product: BitwardenProductType) {
switch (product) {
case BitwardenProductType.PasswordManager:
return this.i18nService.t("passwordManager");
case BitwardenProductType.SecretsManager:
return this.i18nService.t("secretsManager");
default:
return this.i18nService.t("passwordManager");
}
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
@@ -81,6 +101,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
this.userOrg = this.organizationService.get(this.organizationId);
if (this.userOrg.canViewSubscription) {
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
this.lineItems = this.sub?.subscription?.items?.sort(sortSubscriptionItems) ?? [];
}
const apiKeyResponse = await this.organizationApiService.getApiKeyInformation(
@@ -90,7 +111,28 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
(i) => i.keyType === OrganizationApiKeyType.BillingSync
);
this.showSecretsManagerSubscribe =
this.userOrg.canEditSubscription &&
!this.userOrg.useSecretsManager &&
!this.subscription?.cancelled &&
!this.subscriptionMarkedForCancel;
this.showAdjustSecretsManager =
this.userOrg.canEditSubscription &&
this.userOrg.useSecretsManager &&
this.subscription != null &&
this.sub.secretsManagerPlan?.hasAdditionalSeatsOption &&
!this.subscription.cancelled &&
!this.subscriptionMarkedForCancel;
this.loading = false;
// Remove the remaining lines when the sm-ga-billing flag is deleted
const smBillingEnabled = await this.configService.getFeatureFlagBool(
FeatureFlag.SecretsManagerBilling
);
this.showSecretsManagerSubscribe = this.showSecretsManagerSubscribe && smBillingEnabled;
this.showAdjustSecretsManager = this.showAdjustSecretsManager && smBillingEnabled;
}
get subscription() {
@@ -138,6 +180,20 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
return this.sub.seats;
}
get smOptions(): SecretsManagerSubscriptionOptions {
return {
seatCount: this.sub.smSeats,
maxAutoscaleSeats: this.sub.maxAutoscaleSmSeats,
seatPrice: this.sub.secretsManagerPlan.seatPrice,
maxAutoscaleServiceAccounts: this.sub.maxAutoscaleSmServiceAccounts,
additionalServiceAccounts:
this.sub.smServiceAccounts - this.sub.secretsManagerPlan.baseServiceAccount,
interval: this.sub.secretsManagerPlan.isAnnual ? "year" : "month",
additionalServiceAccountPrice: this.sub.secretsManagerPlan.additionalPricePerServiceAccount,
baseServiceAccountCount: this.sub.secretsManagerPlan.baseServiceAccount,
};
}
get maxAutoscaleSeats() {
return this.sub.maxAutoscaleSeats;
}
@@ -332,3 +388,23 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
return this.subscription == null && this.sub.planType === PlanType.Free && !this.showChangePlan;
}
}
/**
* Helper to sort subscription items by product type and then by addon status
*/
function sortSubscriptionItems(
a: BillingSubscriptionItemResponse,
b: BillingSubscriptionItemResponse
) {
if (a.bitwardenProduct == b.bitwardenProduct) {
if (a.addonSubscriptionItem == b.addonSubscriptionItem) {
return 0;
}
// sort addon items to the bottom
if (a.addonSubscriptionItem) {
return 1;
}
return -1;
}
return a.bitwardenProduct - b.bitwardenProduct;
}

View File

@@ -1,13 +0,0 @@
<form *ngIf="showSecretsManager" [formGroup]="formGroup" [bitSubmit]="submit">
<h2 class="spaced-header">{{ "secretsManagerBeta" | i18n }}</h2>
<p>{{ "secretsManagerSubscriptionDesc" | i18n }}</p>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="enabled" />
<bit-label>{{ "secretsManagerEnable" | i18n }}</bit-label>
</bit-form-control>
<button bitButton bitFormButton buttonType="primary" type="submit">
{{ "save" | i18n }}
</button>
</form>

View File

@@ -1,52 +0,0 @@
import { Component, Input, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationEnrollSecretsManagerRequest } from "@bitwarden/common/admin-console/models/request/organization/organization-enroll-secrets-manager.request";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { flagEnabled } from "../../../../utils/flags";
@Component({
selector: "sm-enroll",
templateUrl: "enroll.component.html",
})
export class SecretsManagerEnrollComponent implements OnInit {
@Input() enabled: boolean;
@Input() organizationId: string;
protected formGroup = this.formBuilder.group({
enabled: [false],
});
protected showSecretsManager = false;
constructor(
private formBuilder: FormBuilder,
private organizationApiService: OrganizationApiServiceAbstraction,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private syncService: SyncService
) {
this.showSecretsManager = flagEnabled("secretsManager");
}
ngOnInit(): void {
this.formGroup.setValue({
enabled: this.enabled,
});
}
protected submit = async () => {
this.formGroup.markAllAsTouched();
const request = new OrganizationEnrollSecretsManagerRequest();
request.enabled = this.formGroup.value.enabled;
await this.organizationApiService.updateEnrollSecretsManager(this.organizationId, request);
await this.syncService.fullSync(true);
this.platformUtilsService.showToast("success", null, this.i18nService.t("subscriptionUpdated"));
};
}

View File

@@ -0,0 +1,3 @@
export * from "./sm-billing.module";
export * from "./sm-subscribe.component";
export * from "./sm-subscribe-standalone.component";

View File

@@ -0,0 +1,93 @@
<form [formGroup]="formGroup" [bitSubmit]="submit">
<bit-form-field class="tw-w-2/3">
<bit-label>{{ "subscriptionSeats" | i18n }}</bit-label>
<input bitInput id="smSeatCount" formControlName="seatCount" type="number" step="1" min="1" />
<bit-hint>
<strong>{{ "total" | i18n }}:</strong>
{{ formGroup.value.seatCount || 0 }} &times; {{ options.seatPrice | currency : "$" }} =
{{ seatTotal | currency : "$" }} / {{ options.interval | i18n }}
</bit-hint>
</bit-form-field>
<bit-form-control>
<bit-label>{{ "limitSubscription" | i18n }}</bit-label>
<input type="checkbox" bitCheckbox id="limitSmSeats" formControlName="limitSeats" />
<bit-hint>
{{ "limitSmSubscriptionDesc" | i18n }}
</bit-hint>
</bit-form-control>
<bit-form-field class="tw-w-2/3" *ngIf="formGroup.value.limitSeats">
<bit-label>{{ "maxSeatLimit" | i18n }}</bit-label>
<input
bitInput
id="smSeatLimit"
formControlName="maxAutoscaleSeats"
type="number"
step="1"
[min]="formGroup.value.seatCount"
/>
<bit-hint>
<strong>{{ "maxSeatCost" | i18n }}:</strong>
{{ formGroup.value.maxAutoscaleSeats || 0 }} &times;
{{ options.seatPrice | currency : "$" }} = {{ maxSeatTotal | currency : "$" }} /
{{ options.interval | i18n }}
</bit-hint>
</bit-form-field>
<bit-form-field class="tw-w-2/3">
<bit-label>{{ "additionalServiceAccounts" | i18n }}</bit-label>
<input
bitInput
id="additionalServiceAccountCount"
formControlName="additionalServiceAccounts"
type="number"
step="1"
min="0"
/>
<bit-hint>
<div>
{{
"additionalServiceAccountsDesc"
| i18n : options.baseServiceAccountCount : (monthlyServiceAccountPrice | currency : "$")
}}
</div>
<div>
<strong>{{ "total" | i18n }}:</strong>
{{ formGroup.value.additionalServiceAccounts || 0 }} &times;
{{ options.additionalServiceAccountPrice | currency : "$" }} =
{{ serviceAccountTotal | currency : "$" }} / {{ options.interval | i18n }}
</div>
</bit-hint>
</bit-form-field>
<bit-form-control>
<bit-label>{{ "limitServiceAccounts" | i18n }}</bit-label>
<input
type="checkbox"
bitCheckbox
id="limitServiceAccounts"
formControlName="limitServiceAccounts"
/>
<bit-hint>
{{ "limitServiceAccountsDesc" | i18n }}
</bit-hint>
</bit-form-control>
<bit-form-field class="tw-w-2/3" *ngIf="formGroup.value.limitServiceAccounts">
<bit-label>{{ "serviceAccountLimit" | i18n }}</bit-label>
<input
bitInput
id="additionalServiceAccountLimit"
formControlName="maxAutoscaleServiceAccounts"
type="number"
step="1"
[min]="formGroup.value.additionalServiceAccounts"
/>
<bit-hint>
<strong>{{ "maxServiceAccountCost" | i18n }}:</strong>
{{ formGroup.value.maxAutoscaleServiceAccounts || 0 }} &times;
{{ options.additionalServiceAccountPrice | currency : "$" }} =
{{ maxServiceAccountTotal | currency : "$" }} / {{ options.interval | i18n }}
</bit-hint>
</bit-form-field>
<button type="submit" bitButton buttonType="primary" bitFormButton>
{{ "save" | i18n }}
</button>
<bit-error-summary [formGroup]="formGroup" class="tw-mt-2"></bit-error-summary>
</form>

View File

@@ -0,0 +1,172 @@
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { Subject, takeUntil } from "rxjs";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationSmSubscriptionUpdateRequest } from "@bitwarden/common/billing/models/request/organization-sm-subscription-update.request";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
export interface SecretsManagerSubscriptionOptions {
interval: "year" | "month";
/**
* The current number of seats the organization subscribes to.
*/
seatCount: number;
/**
* Optional auto-scaling limit for the number of seats the organization can subscribe to.
*/
maxAutoscaleSeats: number;
/**
* The price per seat for the subscription.
*/
seatPrice: number;
/**
* The number of service accounts that are included in the base subscription.
*/
baseServiceAccountCount: number;
/**
* The current number of additional service accounts the organization subscribes to.
*/
additionalServiceAccounts: number;
/**
* Optional auto-scaling limit for the number of additional service accounts the organization can subscribe to.
*/
maxAutoscaleServiceAccounts: number;
/**
* The price per additional service account for the subscription.
*/
additionalServiceAccountPrice: number;
}
@Component({
selector: "app-sm-adjust-subscription",
templateUrl: "sm-adjust-subscription.component.html",
})
export class SecretsManagerAdjustSubscriptionComponent implements OnInit, OnDestroy {
@Input() organizationId: string;
@Input() options: SecretsManagerSubscriptionOptions;
@Output() onAdjusted = new EventEmitter();
private destroy$ = new Subject<void>();
formGroup = this.formBuilder.group({
seatCount: [0, [Validators.required, Validators.min(1)]],
limitSeats: [false],
maxAutoscaleSeats: [null as number | null],
additionalServiceAccounts: [0, [Validators.required, Validators.min(0)]],
limitServiceAccounts: [false],
maxAutoscaleServiceAccounts: [null as number | null],
});
get monthlyServiceAccountPrice(): number {
return this.options.interval == "month"
? this.options.additionalServiceAccountPrice
: this.options.additionalServiceAccountPrice / 12;
}
get serviceAccountTotal(): number {
return Math.abs(
this.formGroup.value.additionalServiceAccounts * this.options.additionalServiceAccountPrice
);
}
get seatTotal(): number {
return Math.abs(this.formGroup.value.seatCount * this.options.seatPrice);
}
get maxServiceAccountTotal(): number {
return Math.abs(
(this.formGroup.value.maxAutoscaleServiceAccounts ?? 0) *
this.options.additionalServiceAccountPrice
);
}
get maxSeatTotal(): number {
return Math.abs((this.formGroup.value.maxAutoscaleSeats ?? 0) * this.options.seatPrice);
}
constructor(
private formBuilder: FormBuilder,
private organizationApiService: OrganizationApiServiceAbstraction,
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService
) {}
ngOnInit() {
this.formGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
const maxAutoscaleSeatsControl = this.formGroup.controls.maxAutoscaleSeats;
const maxAutoscaleServiceAccountsControl =
this.formGroup.controls.maxAutoscaleServiceAccounts;
if (value.limitSeats) {
maxAutoscaleSeatsControl.setValidators([Validators.min(value.seatCount)]);
maxAutoscaleSeatsControl.enable({ emitEvent: false });
} else {
maxAutoscaleSeatsControl.disable({ emitEvent: false });
}
if (value.limitServiceAccounts) {
maxAutoscaleServiceAccountsControl.setValidators([
Validators.min(value.additionalServiceAccounts),
]);
maxAutoscaleServiceAccountsControl.enable({ emitEvent: false });
} else {
maxAutoscaleServiceAccountsControl.disable({ emitEvent: false });
}
});
this.formGroup.patchValue({
seatCount: this.options.seatCount,
maxAutoscaleSeats: this.options.maxAutoscaleSeats,
additionalServiceAccounts: this.options.additionalServiceAccounts,
maxAutoscaleServiceAccounts: this.options.maxAutoscaleServiceAccounts,
limitSeats: this.options.maxAutoscaleSeats != null,
limitServiceAccounts: this.options.maxAutoscaleServiceAccounts != null,
});
}
submit = async () => {
this.formGroup.markAllAsTouched();
if (this.formGroup.invalid) {
return;
}
const request = new OrganizationSmSubscriptionUpdateRequest();
request.seatAdjustment = this.formGroup.value.seatCount - this.options.seatCount;
request.serviceAccountAdjustment =
this.formGroup.value.additionalServiceAccounts - this.options.additionalServiceAccounts;
request.maxAutoscaleSeats = this.formGroup.value.limitSeats
? this.formGroup.value.maxAutoscaleSeats
: null;
request.maxAutoscaleServiceAccounts = this.formGroup.value.limitServiceAccounts
? this.formGroup.value.maxAutoscaleServiceAccounts
: null;
await this.organizationApiService.updateSecretsManagerSubscription(
this.organizationId,
request
);
await this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("subscriptionUpdated")
);
this.onAdjusted.emit();
};
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

View File

@@ -0,0 +1,22 @@
import { NgModule } from "@angular/core";
import { SharedModule } from "../../../shared";
import { SecretsManagerAdjustSubscriptionComponent } from "./sm-adjust-subscription.component";
import { SecretsManagerSubscribeStandaloneComponent } from "./sm-subscribe-standalone.component";
import { SecretsManagerSubscribeComponent } from "./sm-subscribe.component";
@NgModule({
imports: [SharedModule],
declarations: [
SecretsManagerSubscribeComponent,
SecretsManagerSubscribeStandaloneComponent,
SecretsManagerAdjustSubscriptionComponent,
],
exports: [
SecretsManagerSubscribeComponent,
SecretsManagerSubscribeStandaloneComponent,
SecretsManagerAdjustSubscriptionComponent,
],
})
export class SecretsManagerBillingModule {}

View File

@@ -0,0 +1,8 @@
<form [formGroup]="formGroup" [bitSubmit]="submit" *ngIf="plan">
<sm-subscribe
[formGroup]="formGroup"
[selectedPlan]="plan"
[upgradeOrganization]="false"
[showSubmitButton]="true"
></sm-subscribe>
</form>

View File

@@ -0,0 +1,46 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { SecretsManagerSubscribeRequest } from "@bitwarden/common/billing/models/request/sm-subscribe.request";
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { secretsManagerSubscribeFormFactory } from "./sm-subscribe.component";
@Component({
selector: "sm-subscribe-standalone",
templateUrl: "sm-subscribe-standalone.component.html",
})
export class SecretsManagerSubscribeStandaloneComponent {
@Input() plan: PlanResponse;
@Input() organization: Organization;
@Output() onSubscribe = new EventEmitter<void>();
formGroup = secretsManagerSubscribeFormFactory(this.formBuilder);
constructor(
private formBuilder: FormBuilder,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private organizationApiService: OrganizationApiServiceAbstraction
) {}
submit = async () => {
const request = new SecretsManagerSubscribeRequest();
request.additionalSmSeats = this.plan.hasAdditionalSeatsOption
? this.formGroup.value.userSeats
: 0;
request.additionalServiceAccounts = this.plan.hasAdditionalServiceAccountOption
? this.formGroup.value.additionalServiceAccounts
: 0;
await this.organizationApiService.subscribeToSecretsManager(this.organization.id, request);
this.platformUtilsService.showToast("success", null, this.i18nService.t("subscriptionUpdated"));
this.onSubscribe.emit();
};
}

View File

@@ -0,0 +1,71 @@
<div *ngIf="formGroup && selectedPlan != null" [formGroup]="formGroup">
<h3 bitTypography="h3">{{ "moreFromBitwarden" | i18n }}</h3>
<div class="tw-rounded-t tw-bg-background-alt3 tw-p-5">
<div class="tw-w-72">
<bit-icon [icon]="logo"></bit-icon>
</div>
</div>
<div
class="tw-rounded-b tw-border-x tw-border-b tw-border-t-0 tw-border-solid tw-border-secondary-300 tw-p-5"
>
<h4 bitTypography="h4">{{ "secretsManagerForPlan" | i18n : planName }}</h4>
<div class="tw-text-muted">
{{ "secretsManagerForPlanDesc" | i18n }}
<ul>
<li *ngIf="product == productTypes.Free">{{ "limitedUsers" | i18n : maxUsers }}</li>
<li>{{ "unlimitedSecrets" | i18n }}</li>
<li *ngIf="product == productTypes.Free; else unlimitedProjects">
{{ "projectsIncluded" | i18n : maxProjects }}
</li>
<ng-template #unlimitedProjects>
<li>{{ "unlimitedProjects" | i18n }}</li>
</ng-template>
<li>{{ "serviceAccountsIncluded" | i18n : serviceAccountsIncluded }}</li>
<li *ngIf="product != productTypes.Free">
{{
"additionalServiceAccountCost" | i18n : (monthlyCostPerServiceAccount | currency : "$")
}}
</li>
</ul>
</div>
<div class="tw-mb-5">
<span *ngIf="product != productTypes.Free; else freeForever">
{{ "costPerUser" | i18n : (monthlyCostPerUser | currency : "$") }} /{{ "month" | i18n }}
</span>
<ng-template #freeForever>
<span>{{ "freeForever" | i18n }}</span>
</ng-template>
</div>
<bit-form-control>
<input type="checkbox" bitCheckbox formControlName="enabled" />
<bit-label>{{ "addSecretsManager" | i18n }}</bit-label>
<bit-hint *ngIf="upgradeOrganization">{{ "addSecretsManagerUpgradeDesc" | i18n }}</bit-hint>
</bit-form-control>
<ng-container *ngIf="formGroup.value.enabled">
<div *ngIf="selectedPlan.hasAdditionalSeatsOption" class="tw-w-1/2">
<bit-form-field>
<bit-label>{{ "userSeats" | i18n }}</bit-label>
<input bitInput formControlName="userSeats" type="number" />
<bit-hint>{{ "userSeatsHowManyDesc" | i18n }}</bit-hint>
</bit-form-field>
</div>
<div *ngIf="selectedPlan.hasAdditionalServiceAccountOption" class="tw-w-1/2">
<bit-form-field>
<bit-label>{{ "additionalServiceAccounts" | i18n }}</bit-label>
<input bitInput formControlName="additionalServiceAccounts" type="number" />
<bit-hint>{{
"additionalServiceAccountsDesc"
| i18n : serviceAccountsIncluded : (monthlyCostPerServiceAccount | currency : "$")
}}</bit-hint>
</bit-form-field>
</div>
<button *ngIf="showSubmitButton" type="submit" bitButton buttonType="primary" bitFormButton>
{{ "save" | i18n }}
</button>
</ng-container>
</div>
</div>

View File

@@ -0,0 +1,104 @@
import { Component, Input, OnDestroy, OnInit } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { Subject, startWith, takeUntil } from "rxjs";
import { ControlsOf } from "@bitwarden/angular/types/controls-of";
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
import { ProductType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { SecretsManagerLogo } from "../../../../../../../bitwarden_license/bit-web/src/app/secrets-manager/layout/secrets-manager-logo";
export interface SecretsManagerSubscription {
enabled: boolean;
userSeats: number;
additionalServiceAccounts: number;
}
export const secretsManagerSubscribeFormFactory = (
formBuilder: FormBuilder
): FormGroup<ControlsOf<SecretsManagerSubscription>> =>
formBuilder.group({
enabled: [false],
userSeats: [1, [Validators.required, Validators.min(1), Validators.max(100000)]],
additionalServiceAccounts: [
0,
[Validators.required, Validators.min(0), Validators.max(100000)],
],
});
@Component({
selector: "sm-subscribe",
templateUrl: "sm-subscribe.component.html",
})
export class SecretsManagerSubscribeComponent implements OnInit, OnDestroy {
@Input() formGroup: FormGroup<ControlsOf<SecretsManagerSubscription>>;
@Input() upgradeOrganization: boolean;
@Input() showSubmitButton = false;
@Input() selectedPlan: PlanResponse;
logo = SecretsManagerLogo;
productTypes = ProductType;
private destroy$ = new Subject<void>();
constructor(private i18nService: I18nService) {}
ngOnInit() {
this.formGroup.controls.enabled.valueChanges
.pipe(startWith(this.formGroup.value.enabled), takeUntil(this.destroy$))
.subscribe((enabled) => {
if (enabled) {
this.formGroup.controls.userSeats.enable();
this.formGroup.controls.additionalServiceAccounts.enable();
} else {
this.formGroup.controls.userSeats.disable();
this.formGroup.controls.additionalServiceAccounts.disable();
}
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
get product() {
return this.selectedPlan.product;
}
get planName() {
switch (this.product) {
case ProductType.Free:
return this.i18nService.t("free2PersonOrganization");
case ProductType.Teams:
return this.i18nService.t("planNameTeams");
case ProductType.Enterprise:
return this.i18nService.t("planNameEnterprise");
}
}
get serviceAccountsIncluded() {
return this.selectedPlan.baseServiceAccount;
}
get monthlyCostPerServiceAccount() {
return this.selectedPlan.isAnnual
? this.selectedPlan.additionalPricePerServiceAccount / 12
: this.selectedPlan.additionalPricePerServiceAccount;
}
get maxUsers() {
return this.selectedPlan.maxUsers;
}
get maxProjects() {
return this.selectedPlan.maxProjects;
}
get monthlyCostPerUser() {
return this.selectedPlan.isAnnual
? this.selectedPlan.seatPrice / 12
: this.selectedPlan.seatPrice;
}
}

View File

@@ -28,7 +28,7 @@
(ngSubmit)="submit()"
[appApiAction]="formPromise"
ngNativeValidate
*ngIf="!loading && !selfHosted && this.plans"
*ngIf="!loading && !selfHosted && this.passwordManagerPlans && this.secretsManagerPlans"
class="tw-pt-6"
>
<app-org-info
@@ -119,7 +119,7 @@
<span *ngIf="selectableProduct.product == productTypes.Free">{{ "freeForever" | i18n }}</span>
</label>
</div>
<div *ngIf="formGroup.controls['product'].value !== productTypes.Free">
<div *ngIf="formGroup.value.product !== productTypes.Free">
<ng-container *ngIf="selectedPlan.hasAdditionalSeatsOption && !selectedPlan.baseSeats">
<h2 class="mt-5">{{ "users" | i18n }}</h2>
<div class="row">
@@ -230,7 +230,8 @@
<span *ngIf="!selectablePlan.baseSeats">{{ "users" | i18n }}:</span>
{{ formGroup.controls["additionalSeats"].value || 0 }} &times;
{{ selectablePlan.seatPrice / 12 | currency : "$" }} &times; 12
{{ "monthAbbr" | i18n }} = {{ seatTotal(selectablePlan) | currency : "$" }} /{{
{{ "monthAbbr" | i18n }} =
{{ seatTotal(selectablePlan, formGroup.value.additionalSeats) | currency : "$" }} /{{
"year" | i18n
}}
</small>
@@ -256,7 +257,9 @@
<span *ngIf="!selectablePlan.baseSeats">{{ "users" | i18n }}:</span>
{{ formGroup.controls["additionalSeats"].value || 0 }} &times;
{{ selectablePlan.seatPrice | currency : "$" }} {{ "monthAbbr" | i18n }} =
{{ seatTotal(selectablePlan) | currency : "$" }} /{{ "month" | i18n }}
{{ seatTotal(selectablePlan, formGroup.value.additionalSeats) | currency : "$" }} /{{
"month" | i18n
}}
</small>
<small *ngIf="selectablePlan.hasAdditionalStorageOption">
{{ "additionalStorageGb" | i18n }}:
@@ -268,8 +271,21 @@
</ng-container>
</label>
</div>
<hr class="my-3" />
<h2 class="spaced-header mb-4">
</div>
<!-- Secrets Manager -->
<div class="tw-my-10">
<sm-subscribe
*ngIf="showSecretsManagerSubscribe && planOffersSecretsManager"
[formGroup]="formGroup.controls.secretsManager"
[selectedPlan]="selectedSecretsManagerPlan"
[upgradeOrganization]="!createOrganization"
></sm-subscribe>
</div>
<!-- Payment info -->
<div *ngIf="formGroup.value.product !== productTypes.Free">
<h2 class="mb-4">
{{ (createOrganization ? "paymentInformation" : "billingInformation") | i18n }}
</h2>
<small class="text-muted font-italic mb-3 d-block">
@@ -279,8 +295,12 @@
<app-tax-info (onCountryChanged)="changedCountry()"></app-tax-info>
<div id="price" class="my-4">
<div class="text-muted text-sm">
{{ "planPrice" | i18n }}: {{ subtotal | currency : "USD $" }}
{{ "passwordManagerPlanPrice" | i18n }}: {{ passwordManagerSubtotal | currency : "USD $" }}
<br />
<span *ngIf="planOffersSecretsManager && formGroup.value.secretsManager.enabled">
{{ "secretsManagerPlanPrice" | i18n }}: {{ secretsManagerSubtotal | currency : "USD $" }}
<br />
</span>
<ng-container>
{{ "estimatedTax" | i18n }}: {{ taxCharges | currency : "USD $" }}
</ng-container>

View File

@@ -7,7 +7,7 @@ import {
Output,
ViewChild,
} from "@angular/core";
import { UntypedFormBuilder, Validators } from "@angular/forms";
import { FormBuilder, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { Subject, takeUntil } from "rxjs";
@@ -20,9 +20,11 @@ import { OrganizationCreateRequest } from "@bitwarden/common/admin-console/model
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
import { BitwardenProductType, PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
import { ProductType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -32,6 +34,8 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { secretsManagerSubscribeFormFactory } from "../organizations/secrets-manager/sm-subscribe.component";
import { PaymentComponent } from "./payment.component";
import { TaxInfoComponent } from "./tax-info.component";
@@ -51,24 +55,29 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
@Input() showFree = true;
@Input() showCancel = false;
@Input() acceptingSponsorship = false;
@Input()
get product(): ProductType {
return this._product;
}
set product(product: ProductType) {
this._product = product;
this.formGroup?.controls?.product?.setValue(product);
}
private _product = ProductType.Free;
@Input()
get plan(): PlanType {
return this._plan;
}
set plan(plan: PlanType) {
this._plan = plan;
this.formGroup?.controls?.plan?.setValue(plan);
}
private _plan = PlanType.Free;
@Input() providerId?: string;
@Output() onSuccess = new EventEmitter<OnSuccessArgs>();
@@ -82,6 +91,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
singleOrgPolicyAppliesToActiveUser = false;
isInTrialFlow = false;
discount = 0;
showSecretsManagerSubscribe: boolean;
secretsManagerSubscription = secretsManagerSubscribeFormFactory(this.formBuilder);
formGroup = this.formBuilder.group({
name: [""],
@@ -94,9 +106,11 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
businessName: [""],
plan: [this.plan],
product: [this.product],
secretsManager: this.secretsManagerSubscription,
});
plans: PlanResponse[];
passwordManagerPlans: PlanResponse[];
secretsManagerPlans: PlanResponse[];
private destroy$ = new Subject<void>();
@@ -111,8 +125,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
private organizationService: OrganizationService,
private logService: LogService,
private messagingService: MessagingService,
private formBuilder: UntypedFormBuilder,
private organizationApiService: OrganizationApiServiceAbstraction
private formBuilder: FormBuilder,
private organizationApiService: OrganizationApiServiceAbstraction,
private configService: ConfigServiceAbstraction
) {
this.selfHosted = platformUtilsService.isSelfHost();
}
@@ -120,7 +135,13 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
async ngOnInit() {
if (!this.selfHosted) {
const plans = await this.apiService.getPlans();
this.plans = plans.data;
this.passwordManagerPlans = plans.data.filter(
(plan) => plan.bitwardenProduct === BitwardenProductType.PasswordManager
);
this.secretsManagerPlans = plans.data.filter(
(plan) => plan.bitwardenProduct === BitwardenProductType.SecretsManager
);
if (this.product === ProductType.Enterprise || this.product === ProductType.Teams) {
this.formGroup.controls.businessOwned.setValue(true);
}
@@ -131,12 +152,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
this.changedOwnedBusiness();
}
if (!this.createOrganization || this.acceptingSponsorship) {
this.formGroup.controls.product.setValue(ProductType.Families);
this.changedProduct();
}
if (this.createOrganization) {
if (!this.createOrganization) {
this.upgradeFlowPrefillForm();
} else {
this.formGroup.controls.name.addValidators([Validators.required, Validators.maxLength(50)]);
this.formGroup.controls.billingEmail.addValidators(Validators.required);
}
@@ -148,6 +166,11 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
this.singleOrgPolicyAppliesToActiveUser = policyAppliesToActiveUser;
});
this.showSecretsManagerSubscribe = await this.configService.getFeatureFlagBool(
FeatureFlag.SecretsManagerBilling,
false
);
this.loading = false;
}
@@ -165,7 +188,15 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
}
get selectedPlan() {
return this.plans.find((plan) => plan.type === this.formGroup.controls.plan.value);
return this.passwordManagerPlans.find(
(plan) => plan.type === this.formGroup.controls.plan.value
);
}
get selectedSecretsManagerPlan() {
return this.secretsManagerPlans.find(
(plan) => plan.type === this.formGroup.controls.plan.value
);
}
get selectedPlanInterval() {
@@ -173,7 +204,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
}
get selectableProducts() {
let validPlans = this.plans.filter((plan) => plan.type !== PlanType.Custom);
let validPlans = this.passwordManagerPlans.filter((plan) => plan.type !== PlanType.Custom);
if (this.formGroup.controls.businessOwned.value) {
validPlans = validPlans.filter((plan) => plan.canBeUsedByBusiness);
@@ -191,7 +222,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
);
if (this.acceptingSponsorship) {
const familyPlan = this.plans.find((plan) => plan.type === PlanType.FamiliesAnnually);
const familyPlan = this.passwordManagerPlans.find(
(plan) => plan.type === PlanType.FamiliesAnnually
);
this.discount = familyPlan.basePrice;
validPlans = [familyPlan];
}
@@ -200,7 +233,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
}
get selectablePlans() {
return this.plans?.filter(
return this.passwordManagerPlans?.filter(
(plan) =>
!plan.legacyYear && !plan.disabled && plan.product === this.formGroup.controls.product.value
);
@@ -231,21 +264,32 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
);
}
seatTotal(plan: PlanResponse): number {
seatTotal(plan: PlanResponse, seats: number): number {
if (!plan.hasAdditionalSeatsOption) {
return 0;
}
return plan.seatPrice * Math.abs(this.formGroup.controls.additionalSeats.value || 0);
return plan.seatPrice * Math.abs(seats || 0);
}
get subtotal() {
additionalServiceAccountTotal(plan: PlanResponse): number {
if (!plan.hasAdditionalServiceAccountOption) {
return 0;
}
return (
plan.additionalPricePerServiceAccount *
Math.abs(this.secretsManagerForm.value.additionalServiceAccounts || 0)
);
}
get passwordManagerSubtotal() {
let subTotal = this.selectedPlan.basePrice;
if (
this.selectedPlan.hasAdditionalSeatsOption &&
this.formGroup.controls.additionalSeats.value
) {
subTotal += this.seatTotal(this.selectedPlan);
subTotal += this.seatTotal(this.selectedPlan, this.formGroup.value.additionalSeats);
}
if (
this.selectedPlan.hasAdditionalStorageOption &&
@@ -262,18 +306,39 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
return subTotal - this.discount;
}
get secretsManagerSubtotal() {
const plan = this.selectedSecretsManagerPlan;
const formValues = this.secretsManagerForm.value;
if (!this.planOffersSecretsManager || !formValues.enabled) {
return 0;
}
let subTotal = plan.basePrice;
if (plan.hasAdditionalSeatsOption && formValues.userSeats) {
subTotal += this.seatTotal(plan, formValues.userSeats);
}
if (plan.hasAdditionalStorageOption && formValues.additionalServiceAccounts) {
subTotal += this.additionalServiceAccountTotal(this.selectedPlan);
}
return subTotal;
}
get freeTrial() {
return this.selectedPlan.trialPeriodDays != null;
}
get taxCharges() {
return this.taxComponent != null && this.taxComponent.taxRate != null
? (this.taxComponent.taxRate / 100) * this.subtotal
? (this.taxComponent.taxRate / 100) *
(this.passwordManagerSubtotal + this.secretsManagerSubtotal)
: 0;
}
get total() {
return this.subtotal + this.taxCharges || 0;
return this.passwordManagerSubtotal + this.secretsManagerSubtotal + this.taxCharges || 0;
}
get paymentDesc() {
@@ -286,6 +351,14 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
}
}
get secretsManagerForm() {
return this.formGroup.controls.secretsManager;
}
get planOffersSecretsManager() {
return this.selectedSecretsManagerPlan != null;
}
changedProduct() {
this.formGroup.controls.plan.setValue(this.selectablePlans[0].type);
if (!this.selectedPlan.hasPremiumAccessOption) {
@@ -303,6 +376,14 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
) {
this.formGroup.controls.additionalSeats.setValue(1);
}
if (this.planOffersSecretsManager) {
this.secretsManagerForm.enable();
} else {
this.secretsManagerForm.disable();
}
this.secretsManagerForm.updateValueAndValidity();
}
changedOwnedBusiness() {
@@ -407,6 +488,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
request.billingAddressCountry = this.taxComponent.taxInfo.country;
request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode;
// Secrets Manager
this.buildSecretsManagerRequest(request);
// Retrieve org info to backfill pub/priv key if necessary
const org = await this.organizationService.get(this.organizationId);
if (!org.hasPublicAndPrivateKeys) {
@@ -462,6 +546,9 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
}
}
// Secrets Manager
this.buildSecretsManagerRequest(request);
if (this.providerId) {
const providerRequest = new ProviderOrganizationCreateRequest(
this.formGroup.controls.clientOwnerEmail.value,
@@ -517,4 +604,40 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
return text;
}
private buildSecretsManagerRequest(
request: OrganizationCreateRequest | OrganizationUpgradeRequest
): void {
const formValues = this.secretsManagerForm.value;
request.useSecretsManager = this.planOffersSecretsManager && formValues.enabled;
if (!request.useSecretsManager) {
return;
}
if (this.selectedSecretsManagerPlan.hasAdditionalSeatsOption) {
request.additionalSmSeats = formValues.userSeats;
}
if (this.selectedSecretsManagerPlan.hasAdditionalServiceAccountOption) {
request.additionalServiceAccounts = formValues.additionalServiceAccounts;
}
}
private upgradeFlowPrefillForm() {
if (this.acceptingSponsorship) {
this.formGroup.controls.product.setValue(ProductType.Families);
this.changedProduct();
return;
}
// If they already have SM enabled, bump them up to Teams and enable SM to maintain this access
const organization = this.organizationService.get(this.organizationId);
if (organization.useSecretsManager) {
this.formGroup.controls.product.setValue(ProductType.Teams);
this.secretsManagerForm.controls.enabled.setValue(true);
this.changedProduct();
}
}
}

View File

@@ -38,14 +38,13 @@ export class InitService {
init() {
return async () => {
// Workaround to ignore stateService.activeAccount until process.env.URLS are set
// TODO: Remove this when implementing ticket PM-2637
this.environmentService.initialized = false;
await this.stateService.init();
const urls = process.env.URLS as Urls;
urls.base ??= this.win.location.origin;
this.environmentService.setUrls(urls);
await this.environmentService.setUrls(urls);
// Workaround to ignore stateService.activeAccount until process.env.URLS are set
// TODO: Remove this when implementing ticket PM-2637
this.environmentService.initialized = true;
setTimeout(() => this.notificationsService.init(), 3000);

View File

@@ -51,6 +51,7 @@ import { UpdatePasswordComponent } from "../auth/update-password.component";
import { UpdateTempPasswordComponent } from "../auth/update-temp-password.component";
import { VerifyEmailTokenComponent } from "../auth/verify-email-token.component";
import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.component";
import { SecretsManagerBillingModule } from "../billing/organizations/secrets-manager/sm-billing.module";
import { AddCreditComponent } from "../billing/settings/add-credit.component";
import { AdjustPaymentComponent } from "../billing/settings/adjust-payment.component";
import { BillingHistoryViewComponent } from "../billing/settings/billing-history-view.component";
@@ -125,6 +126,9 @@ import { SharedModule } from "./shared.module";
DynamicAvatarComponent,
EnvironmentSelectorModule,
AccountFingerprintComponent,
// To be removed when OrganizationPlansComponent is moved to its own module (see AC-1453)
SecretsManagerBillingModule,
],
declarations: [
AcceptEmergencyComponent,

View File

@@ -23,6 +23,7 @@ import {
LinkModule,
MenuModule,
MultiSelectModule,
ProgressModule,
RadioButtonModule,
SelectModule,
TableModule,
@@ -69,6 +70,7 @@ import "./locales";
LinkModule,
MenuModule,
MultiSelectModule,
ProgressModule,
RadioButtonModule,
TableModule,
TabsModule,
@@ -103,6 +105,7 @@ import "./locales";
LinkModule,
MenuModule,
MultiSelectModule,
ProgressModule,
RadioButtonModule,
SelectModule,
TableModule,

View File

@@ -8,7 +8,7 @@
<div class="card-body">
<bit-color-password
[password]="type === 'password' ? password : username"
appSelectCopy
[appCopyText]="type === 'password' ? password : username"
></bit-color-password>
</div>
</div>

View File

@@ -10,7 +10,7 @@
<bit-color-password
[password]="h.password"
class="tw-block tw-font-mono"
appSelectCopy
[appCopyText]="h.password"
></bit-color-password>
<small bitTypography="body2" class="tw-text-muted">
{{ h.date | date : "medium" }}

File diff suppressed because it is too large Load Diff

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "تسجيل الدخول باستخدام جهاز"
},
"loginWithDeviceEnabledInfo": {
"message": "تسجيل الدخول باستخدام الجهاز يجب أن يكون مفعلاً في إعدادات تطبيق بيتواردن على هاتفك. هل تحتاج إلى خِيار آخر؟"
"loginWithDeviceEnabledNote": {
"message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?"
},
"loginWithMasterPassword": {
"message": "تسجيل الدخول باستخدام كلمة المرور الرئيسية"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Account recovery administration"
},
"accountRecoveryPolicyDescription": {
"message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Members in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatic enrollment"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "All members will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Members already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Require new members to be enrolled automatically"
},
@@ -5224,8 +5221,8 @@
"message": "Use the",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "require single-sign-on authentication policy",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Trusted device encryption"
},
"memberDecryptionTdeDescriptionStart": {
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "account recovery administration policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ not found",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Cihazla giriş et"
},
"loginWithDeviceEnabledInfo": {
"message": "Cihazla giriş etmə, Bitwarden mobil tətbiqinin tənzimləmələrində fəallaşdırılmalıdır. Başqa bir seçimə ehtiyacınız var?"
"loginWithDeviceEnabledNote": {
"message": "Cihazla giriş etmə, Bitwarden tətbiqinin tənzimləmələrində quraşdırılmalıdır. Başqa bir seçimə ehtiyacınız var?"
},
"loginWithMasterPassword": {
"message": "Ana parolla giriş et"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Hesab bərpa idarəsi"
},
"accountRecoveryPolicyDescription": {
"message": "Ana parol və ya güvənilən cihazlar unudulanda və ya itəndə üzv hesablarını bərpa edin. Bərpa prosesləri, hesab şifrələmə üsuluna əsaslanır."
"accountRecoveryPolicyDesc": {
"message": "Şifrələmə üsuluna əsasən, ana parollar və güvənilən cihazlar unudulduqda və ya itirildikdə hesabları bərpa edin."
},
"resetPasswordPolicyWarning": {
"message": "Administratorların ana parolları sıfırlaya bilməsi üçün təşkilatdakı istifadəçilər öz-özünə və ya avtomatik olaraq qeydiyyatdan keçməlidir."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Avtomatik qeydiyyat"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Dəvətləri qəbul edən kimi bütün istifadəçilər avtomatik olaraq \"parol sıfırlama\"da qeydiyyata alınacaq."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Hal-hazırda təşkilatdakı istifadəçilər, \"parol sıfırlama\"da retroaktiv (geriyə yönələn) olaraq qeydiyyata alınmayacaq. Administratorlar ana parollarını sıfırlaya bilməsi üçün öz-özünə qeydiyyatdan keçməlidirilər."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Yeni istifadəçiləri avtomatik qeydiyyata al"
},
@@ -5224,8 +5221,8 @@
"message": "Bütün üzvlərin SSO ilə",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "giriş etməsini məcburi etmək üçün",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6627,7 +6624,7 @@
"message": "Secrets Manager"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "\"Secrets Manager\"ə istifadəçi müraciətini aktivləşdir."
},
"userAccessSecretsManagerGA": {
"message": "This user can access Secrets Manager"
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Güvənli cihaz şifrələməsi"
},
"memberDecryptionTdeDescriptionStart": {
"message": "Kimlik təsdiqləndikdən sonra üzvlər, cihazlarından saxlanılan açarı istifadə edərək anbar verilənlərinin şifrələrini aça biləcək.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartOne": {
"message": "Kimlik təsdiqləndikdən sonra üzvlər, cihazlarından saxlanılan açarı istifadə edərək anbar verilənlərinin şifrələrini aça biləcək",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "Hesab bərpa idarəsi siyasəti",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "tək təşkilat",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "Bu seçim istifadə edildikdə avto-qeydiyyat ilə işə salınacaq.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "siyasət və ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "hesab bərpa administrasiyası",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "bu seçim istifadə edildikdə avto-qeydiyyat ilə işə salınacaq.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ tapılmadı",
@@ -6859,58 +6864,58 @@
"message": "İstifadəçi, hesab bərpası vasitəsilə verilən bir parolu güncəllədi."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "\"Secrets Manager\"ə müraciət aktivləşdirildi",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Müraciəti aktivləşdir"
},
"bulkEnableSecretsManagerDescription": {
"message": "Grant the following members access to Secrets Manager. The role granted in the Password Manager will apply to Secrets Manager.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "\"Secrets Manager\"i aktivləşdir"
},
"yourOrganizationsFingerprint": {
"message": "Təşkilatınızın barmaq izi ifadəsi",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their organization's public key with another user, for the purposes of sharing."
},
"deviceApprovals": {
"message": "Device approvals"
"message": "Cihaz təsdiqləri"
},
"deviceApprovalsDesc": {
"message": "Approve login requests below to allow the requesting member to finish logging in. Unapproved requests expire after 1 week. Verify the members information before approving."
},
"deviceInfo": {
"message": "Device info"
"message": "Cihaz məlumatı"
},
"time": {
"message": "Time"
"message": "Vaxt"
},
"denyAllRequests": {
"message": "Deny all requests"
"message": "Bütün tələbləri rədd et"
},
"denyRequest": {
"message": "Deny request"
"message": "Tələbi rədd et"
},
"approveRequest": {
"message": "Approve request"
"message": "Tələbi təsdiqlə"
},
"noDeviceRequests": {
"message": "No device requests"
"message": "Heç bir cihaz tələbi yoxdur"
},
"noDeviceRequestsDesc": {
"message": "Member device approval requests will appear here"
"message": "Üzv cihaz təsdiq tələbləri burada görünəcək"
},
"loginRequestDenied": {
"message": "Login request denied"
"message": "Giriş tələbi rədd edildi"
},
"allLoginRequestsDenied": {
"message": "All login requests denied"
"message": "Bütün giriş tələbləri rədd edildi"
},
"loginRequestApproved": {
"message": "Login request approved"
"message": "Giriş tələbi təsdiqləndi"
},
"removeOrgUserNoMasterPasswordTitle": {
"message": "Hesabın ana parolu yoxdur"

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Увайсці з прыладай"
},
"loginWithDeviceEnabledInfo": {
"message": "Неабходна ўключыць уваход з прыладай у наладах мабільнай праграмы Bitwarden. Неабходны іншы варыянт?"
"loginWithDeviceEnabledNote": {
"message": "Неабходна наладзіць уваход з прыладай у наладах мабільнай праграмы Bitwarden. Патрабуецца іншы варыянт?"
},
"loginWithMasterPassword": {
"message": "Увайсці з асноўным паролем"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Адміністраванне аднаўлення ўліковага запісу"
},
"accountRecoveryPolicyDescription": {
"message": "Аднаўленне ўліковага запісу ўдзельніка, калі асноўны пароль забыты або давераная прылада страчана. Працэс аднаўлення заснаваны на метадзе шыфравання ўліковага запісу."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Карыстальнікі арганізацыі павінны зарэгістравацца самастойна або быць зарэгістраванымі аўтаматычна, каб адміністратары маглі скінуць іх асноўны пароль."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Аўтаматычная рэгістрацыя"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Усе карыстальнікі будуць аўтаматычна зарэгістраваны на скіданне пароля, пасля таго як іх запрашэнне будзе прынята і ім не будзе дазволена адмовіцца ад яго выканання."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Карыстальнікі, якія ўжо ўваходзяць у арганізацыю не змогуць зарэгістравацца на скіданне пароля папярэднім чыслом. Яны павінны будуць самастойна зарэгістравацца, перад тым як адміністратары змогуць скінуць іх асноўны пароль."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Аўтаматычна рэгістраваць новых карыстальнікаў"
},
@@ -5224,8 +5221,8 @@
"message": "Выкарыстоўваць",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "абавязковую палітыку аўтэнтыфікацыі адзінага ўваходу (SSO)",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6627,7 +6624,7 @@
"message": "Менеджар сакрэтаў"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "Актываваць доступ карыстальнікаў да менеджара сакрэтаў."
},
"userAccessSecretsManagerGA": {
"message": "Гэты карыстальнік можа атрымаць доступ да менеджара сакрэтаў"
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Шыфраванне даверанай прылады"
},
"memberDecryptionTdeDescriptionStart": {
"message": "Пасля аўтэнтыфікацыі ўдзельнікі расшыфроўваюць даныя сховішча з выкарыстаннем ключа, якія захоўваецца на іх прыладах",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "Палітыка адміністравання аднаўлення ўліковых запісаў",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "з аўтаматычнай рэгістрацыяй уключаецца пры выкарыстанні гэтага параметра.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ не знойдзены",
@@ -6859,18 +6864,18 @@
"message": "Карыстальнік абнавіў пароль пры аднаўленні ўліковага запісу."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "Доступ карыстальнікаў да менеджара сакрэтаў актываваны",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Актываваць доступ"
},
"bulkEnableSecretsManagerDescription": {
"message": "Забяспечце доступ наступным удзельнікам да менеджара сакрэтаў. Роля, якая забяспечана ў менеджары пароляў будзе ўжывацца і да менеджара сакрэтаў.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "Актываваць менеджар сакрэтаў"
},
"yourOrganizationsFingerprint": {
"message": "Фраза адбітку пальца вашай арганізацыі",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Вписване с устройство"
},
"loginWithDeviceEnabledInfo": {
"message": "Вписването с устройство трябва да е включено в настройките на мобилното приложение на Битуорден. Друга настройка ли търсите?"
"loginWithDeviceEnabledNote": {
"message": "Вписването с устройство трябва да е включено в настройките на приложението на Битуорден. Друга настройка ли търсите?"
},
"loginWithMasterPassword": {
"message": "Вписване с главната парола"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Управление на възстановяването на профили"
},
"accountRecoveryPolicyDescription": {
"message": "Можете да възстановявате профилите на потребителите, когато загубят или забравят своята главна парола или доверено устройство. Процесът по възстановяване се основава на метод на шифроване на профила."
"accountRecoveryPolicyDesc": {
"message": "Според метода на шифроване, регистрациите ще бъдат възстановени при забравяне на главна парола или загуба на доверено устройство."
},
"resetPasswordPolicyWarning": {
"message": "Потребителите в организацията ще трябва да се включат сами или да бъдат включени автоматично, преди администраторите да могат да сменят главните им пароли."
"accountRecoveryPolicyWarning": {
"message": "Текущо регистрираните потребители използващи главни пароли ще трябва да се включат сами, преди администраторите да могат да възстановят регистрациите им. Автоматичното включване ще активира възстановяването на регистрациите за новите членове."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Автоматично включване"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Всички потребители ще бъдат включени автоматично в смяната на пароли след като приемат поканите си."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Потребителите, които вече са част от организацията, няма да бъдат включени в смяната на паролите. Те ще трябва да се включат сами, преди администраторите да могат да сменят главните им пароли."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Автоматично включване на новите потребители"
},
@@ -5224,8 +5221,8 @@
"message": "Включете",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "еднократното удостоверяване",
"ssoPolicyHelpAnchor": {
"message": "политиката за изискване на еднократно удостоверяване",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6627,7 +6624,7 @@
"message": "Управление на тайни"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "Включване на достъпа на потребителите до Управлението на тайни."
},
"userAccessSecretsManagerGA": {
"message": "Този потребител има достъп до Управлението на тайни"
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Шифроване чрез доверено устройство"
},
"memberDecryptionTdeDescriptionStart": {
"message": "След вписване, членовете ще дешифрират данните от трезорите си чрез ключ, който се съхранява на устройство.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartOne": {
"message": "След вписване, членовете ще дешифрират данните от трезорите си чрез ключ, който се съхранява на устройство. Политиката за",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "Политиката за управление на възстановяването на профили",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "единствена организация",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"memberDecryptionTdeDescriptionPartTwo": {
"message": "и тази за ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "управление на възстановяването на регистрации",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "с автоматично включване ще бъде активирана при използването на тази настройка.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "Няма намерен $RESOURCE$",
@@ -6859,18 +6864,18 @@
"message": "Потребителят промени парола издадена чрез възстановяването на профили."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "Достъпът до Управлението на тайни е включен",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Включване на достъпа"
},
"bulkEnableSecretsManagerDescription": {
"message": "Дайте на следните членове достъп до Управлението на тайни. Ролята, която всеки от тях има в Управителя на пароли, ще се приложи и в Управлението на тайни.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "Включване на Управлението на тайни"
},
"yourOrganizationsFingerprint": {
"message": "Уникална фраза, идентифицираща организацията ви",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Log in with device"
},
"loginWithDeviceEnabledInfo": {
"message": "Log in with device must be set up in the settings of the Bitwarden mobile app. Need another option?"
"loginWithDeviceEnabledNote": {
"message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?"
},
"loginWithMasterPassword": {
"message": "Log in with master password"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Account recovery administration"
},
"accountRecoveryPolicyDescription": {
"message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Members in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatic enrollment"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "All members will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Members already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Require new members to be enrolled automatically"
},
@@ -5224,8 +5221,8 @@
"message": "Use the",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "require single-sign-on authentication policy",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Trusted device encryption"
},
"memberDecryptionTdeDescriptionStart": {
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "account recovery administration policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ not found",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Log in with device"
},
"loginWithDeviceEnabledInfo": {
"message": "Log in with device must be set up in the settings of the Bitwarden mobile app. Need another option?"
"loginWithDeviceEnabledNote": {
"message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?"
},
"loginWithMasterPassword": {
"message": "Log in with master password"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Account recovery administration"
},
"accountRecoveryPolicyDescription": {
"message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Members in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatic enrollment"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "All members will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Members already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Require new members to be enrolled automatically"
},
@@ -5224,8 +5221,8 @@
"message": "Use the",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "require single-sign-on authentication policy",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Trusted device encryption"
},
"memberDecryptionTdeDescriptionStart": {
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "account recovery administration policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ not found",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Inici de sessió amb dispositiu"
},
"loginWithDeviceEnabledInfo": {
"message": "L'inici de sessió amb el dispositiu ha d'estar activat a la configuració de l'aplicació mòbil Bitwarden. Necessiteu una altra opció?"
"loginWithDeviceEnabledNote": {
"message": "L'inici de sessió amb el dispositiu ha d'estar activat a la configuració de l'aplicació Bitwarden. Necessiteu una altra opció?"
},
"loginWithMasterPassword": {
"message": "Inici de sessió amb contrasenya mestra"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Administració de recuperació de comptes"
},
"accountRecoveryPolicyDescription": {
"message": "Recupereu els comptes dels membres quan s'obliden o perden la contrasenya mestra o els dispositius de confiança. El procés de recuperació es basa en el mètode de xifratge del compte."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Els usuaris de lorganització hauran de registrar-se o ser registrats abans que els administradors puguen restablir la seua contrasenya mestra."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Inscripció automàtica"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Una vegada s'accepte la invitació, tots els usuaris s'inscriuran automàticament al restabliment de la contrasenya."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Els usuaris que ja formen part de lorganització no sinscriuran retroactivament al restabliment de la contrasenya. Hauran de registrar-se abans que els administradors puguen restablir la seua contrasenya mestra."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Inscriviu automàticament usuaris nous"
},
@@ -5224,8 +5221,8 @@
"message": "Habilita la",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "Política d'autenticació SSO",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6627,7 +6624,7 @@
"message": "Administrador de secrets"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "Activa l'accés dels usuaris a l'administrador de secrets."
},
"userAccessSecretsManagerGA": {
"message": "Aquest usuari pot accedir a l'administrador de secrets"
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Encriptació de dispositius de confiança"
},
"memberDecryptionTdeDescriptionStart": {
"message": "Una vegada autenticats, els membres desxifraran les dades de la caixa forta mitjançant una clau emmagatzemada al seu dispositiu. El",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "política d'administració de recuperació de comptes",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "amb inscripció automàtica s'activarà quan s'utilitze aquesta opció.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "No s'ha trobat $RESOURCE$",
@@ -6859,18 +6864,18 @@
"message": "L'usuari ha actualitzat una contrasenya emesa mitjançant la recuperació del compte."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "Activa l'accés a l'administrador de secrets",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Activa l'accés"
},
"bulkEnableSecretsManagerDescription": {
"message": "Concedeix als membres següents accés a l'administrador de secrets. El rol concedit l'administrador de contrasenyes s'aplicarà a l'administrador de secrets.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "Activa l'administrador de secrets"
},
"yourOrganizationsFingerprint": {
"message": "Frase d'empremta digital de l'organització",
@@ -6931,7 +6936,7 @@
"message": "La supressió de membres que no tenen contrasenyes mestres sense establir-ne una pot restringir l'accés al seu compte complet."
},
"startYour7DayFreeTrialOfBitwardenFor": {
"message": "Start your 7-Day free trial of Bitwarden for $ORG$",
"message": "Inicieu la vostra prova gratuïta de 7 dies de Bitwarden per a $ORG$",
"placeholders": {
"org": {
"content": "$1",
@@ -6940,15 +6945,15 @@
}
},
"next": {
"message": "Next"
"message": "Següent"
},
"usFlag": {
"message": "US flag"
"message": "Bandera EUA"
},
"euFlag": {
"message": "EU flag"
"message": "Bandera UE"
},
"selectedRegionFlag": {
"message": "Selected region flag"
"message": "Bandera de la regió seleccionada"
}
}

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Přihlásit se zařízením"
},
"loginWithDeviceEnabledInfo": {
"message": "Přihlášení zařízením musí být nastaveno v mobilní aplikaci Bitwarden. Potřebujete další volby?"
"loginWithDeviceEnabledNote": {
"message": "Přihlášení zařízením musí být nastaveno v aplikaci Bitwarden. Potřebujete další volby?"
},
"loginWithMasterPassword": {
"message": "Přihlásit se pomocí hlavního hesla"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Správa obnovení účtu"
},
"accountRecoveryPolicyDescription": {
"message": "Obnovečlenských účtů při zapomenutí hlavního hesla nebo ztrátě důvěryhodných zařízení. Procesy obnovení jsou založeny na metodě šifrování účtu."
"accountRecoveryPolicyDesc": {
"message": "Na základě metody šifrovámůžete obnovit účty v případě zapomenutí nebo ztráty hlavních hesel nebo důvěryhodných zařízení."
},
"resetPasswordPolicyWarning": {
"message": "Uživatelé v organizaci se budou muset sami zaregistrovat nebo být automaticky zaregistrovaní předtím, než budou moci administrátoři resetovat jejich hlavní heslo."
"accountRecoveryPolicyWarning": {
"message": "U stávajících účtů s hlavními hesly se budou muset členové sami přihlásit, aby mohli správci obnovit jejich účty. Automatická registrace zapne obnovení účtu pro nové členy."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "Před aktivací této zásady musí být povolena jednotná pravidla organizace."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatická registrace"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Jakmile bude jejich pozvání přijato, všichni uživatelé budou automaticky zaregistrováni do resetování hesla."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Uživatelé, kteří jsou již v organizaci, nebudou zpětně zaregistrováni do obnovení hesla. Než budou moci správci obnovit hlavní heslo, budou se muset zaregistrovat sami."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Automaticky zaregistrovat nové uživatele"
},
@@ -5224,7 +5221,7 @@
"message": "Použít",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"ssoPolicyHelpAnchor": {
"message": "vyžadování zásad ověření jednotným přihlášením",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
@@ -6627,7 +6624,7 @@
"message": "Správce tajných klíčů"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "Aktivuje přístup uživatele ke správci tajných klíčů."
},
"userAccessSecretsManagerGA": {
"message": "Tento uživatel může přistupovat ke správci tajných klíčů"
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Šifrování důvěryhodného zařízení"
},
"memberDecryptionTdeDescriptionStart": {
"memberDecryptionTdeDescriptionPartOne": {
"message": "Po ověření budou členové dešifrovat data v trezoru pomocí klíče uloženého na jejich zařízení. ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "Pokud bude tato volba aktivována, ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "Při použití této možnosti ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "budou použity zásady obnovení účtu s automatickým zápisem.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "se zapne zásada jednotné organizace ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "a zásada správy obnovení účtu ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "s automatickým zápisem.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ nebyl nalezen",
@@ -6859,18 +6864,18 @@
"message": "Uživatel aktualizoval heslo vydané prostřednictvím obnovení účtu."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "Aktivován přístup uživatele ke správci tajných klíčů",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Aktivovat přístup"
},
"bulkEnableSecretsManagerDescription": {
"message": "Udělte následujícím členům přístup ke správci tajných klíčů. Role udělená ve správci hesel se bude vztahovat na správce tajných klíčů.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "Aktivovat správce tajných klíčů"
},
"yourOrganizationsFingerprint": {
"message": "Fráze otisku prstu Vaší organizace",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Log in with device"
},
"loginWithDeviceEnabledInfo": {
"message": "Log in with device must be set up in the settings of the Bitwarden mobile app. Need another option?"
"loginWithDeviceEnabledNote": {
"message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?"
},
"loginWithMasterPassword": {
"message": "Log in with master password"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Account recovery administration"
},
"accountRecoveryPolicyDescription": {
"message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Members in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatic enrollment"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "All members will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Members already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Require new members to be enrolled automatically"
},
@@ -5224,8 +5221,8 @@
"message": "Use the",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "require single-sign-on authentication policy",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Trusted device encryption"
},
"memberDecryptionTdeDescriptionStart": {
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "account recovery administration policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ not found",

View File

@@ -618,8 +618,8 @@
"loginWithDevice": {
"message": "Log ind med enhed"
},
"loginWithDeviceEnabledInfo": {
"message": "Log ind med enhed skal være opsat i indstillingerne i Bitwarden mobil-appen. Behov for en anden mulighed?"
"loginWithDeviceEnabledNote": {
"message": "Log ind med enhed skal være opsat i indstillingerne i Bitwarden-appen. Brug for en anden mulighed?"
},
"loginWithMasterPassword": {
"message": "Log ind med hovedadgangskode"
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Kontogendannelseshåndtering"
},
"accountRecoveryPolicyDescription": {
"message": "Gendan medlemskonti, når hovedadgangskode eller betroede enheder er glemt eller tabt. Gendannelsesprocesser er baseret på kontokrypteringsmetoden."
"accountRecoveryPolicyDesc": {
"message": "Gendanner baseret på krypteringsmetoden konti, når hovedadgangskoder eller betroede enheder er glemt eller tabt."
},
"resetPasswordPolicyWarning": {
"message": "Organisationsmedlemmer skal selvindrullere eller være auto-indrulleret, før admins kan nulstille deres hovedadgangskode."
"accountRecoveryPolicyWarning": {
"message": "For eksisterende konti med hovedadgangskoder kræves, at medlemmer selv-indrullere sig, før administratorer kan gendanne deres konti. Automatisk indrullering vil slå kontogendannelse til for nye medlemmer."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "Enkeltorganisations Virksomhedspolitik skal være slået til, før denne politik aktiveres."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Auto-indrullering"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Adgangskodenulstilling indrullerer automatisk alle medlemmer (uden mulighed for afmelding), når deres invitation accepteres."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Adgangskodenulstilling indrullerer ikke allerede eksisterernde organisationmedlemmer med tilbagevirkende kraft. De skal selvindrullere, før admins kan nulstille deres hovedadgangskode."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Kræv auto-indrullering af nye brugere"
},
@@ -5224,7 +5221,7 @@
"message": "Brug",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"ssoPolicyHelpAnchor": {
"message": "kræv Single Sign-On godkendelsespolitik",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
@@ -6627,7 +6624,7 @@
"message": "Hemmelighedshåndtering"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "Aktivér brugeradgang til Hemmelighedshåndtering."
},
"userAccessSecretsManagerGA": {
"message": "Denne bruger kan tilgå Hemmelighedshåndtering"
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Betroet enhed-kryptering"
},
"memberDecryptionTdeDescriptionStart": {
"message": "Når godkendt, dekrypterer medlemmet boksdata vha. en nøgle gemt på enheden.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartOne": {
"message": "Når godkendt, dekrypterer medlemmet boksdata vha. en nøgle gemt på deres enhed. ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "Kontogendannelseshåndteringspolitikken",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "Enkeltorganisationspolitik",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "med automatisk indrullering aktiveres ved brug af denne indstilling.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "og ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "kontogendannelseshåndteringspolitik",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "med automatisk indrullering slås til ved brug af denne indstilling.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ ikke fundet",
@@ -6859,18 +6864,18 @@
"message": "Bruger har opdateret en adgangskode udstedt via kontogendannelse."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "Aktivér adgang til Hemmelighedshåndtering",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Aktivere adgang"
},
"bulkEnableSecretsManagerDescription": {
"message": "Tildel flg. medlemmers adgang til Hemmelighedshåndtering. Den i Adgangskodehåndtering tildelte rolle vil gælde for Hemmelighedshåndtering.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "Aktivere Hemmelighedshåndtering"
},
"yourOrganizationsFingerprint": {
"message": "Din organisations fingeraftrykssætning",

View File

@@ -618,7 +618,7 @@
"loginWithDevice": {
"message": "Mit Gerät anmelden"
},
"loginWithDeviceEnabledInfo": {
"loginWithDeviceEnabledNote": {
"message": "Die Anmeldung über ein Gerät muss in den Einstellungen der Bitwarden App eingerichtet werden. Benötigst du eine andere Option?"
},
"loginWithMasterPassword": {
@@ -4594,21 +4594,18 @@
"accountRecoveryPolicy": {
"message": "Kontowiederherstellungsverwaltung"
},
"accountRecoveryPolicyDescription": {
"message": "Mitgliederkonten wiederherstellen, falls das Master-Passwort oder vertrauenswürdige Geräte vergessen werden oder verloren gehen. Der Wiederherstellungsprozess basiert auf der Verschlüsselungsmethode des Kontos."
"accountRecoveryPolicyDesc": {
"message": "Based on the encryption method, recover accounts when master passwords or trusted devices are forgotten or lost."
},
"resetPasswordPolicyWarning": {
"message": "Benutzer in der Organisation müssen sich selbst registrieren oder automatisch registriert sein, bevor Administratoren deren Master-Passwort zurücksetzen können."
"accountRecoveryPolicyWarning": {
"message": "Existing accounts with master passwords will require members to self-enroll before administrators can recover their accounts. Automatic enrollment will turn on account recovery for new members."
},
"accountRecoverySingleOrgRequirementDesc": {
"message": "The single organization Enterprise policy must be turned on before activating this policy."
},
"resetPasswordPolicyAutoEnroll": {
"message": "Automatische Registrierung"
},
"resetPasswordPolicyAutoEnrollDescription": {
"message": "Alle Benutzer werden automatisch für die Passwortzurücksetzung registriert, sobald ihre Einladung angenommen wurde und können sich nicht davon abmelden."
},
"resetPasswordPolicyAutoEnrollWarning": {
"message": "Benutzer, die bereits in der Organisation sind, werden nicht rückwirkend für Passwortzurücksetzung registriert. Sie müssen sich selbst registrieren, bevor Administratoren deren Master-Passwort zurücksetzen können."
},
"resetPasswordPolicyAutoEnrollCheckbox": {
"message": "Neue Mitglieder müssen automatisch registriert werden"
},
@@ -5224,8 +5221,8 @@
"message": "Aktiviere die",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpLink": {
"message": "SSO-Authentifizierungsrichtlinie",
"ssoPolicyHelpAnchor": {
"message": "require single sign-on authentication policy",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'"
},
"ssoPolicyHelpEnd": {
@@ -6627,7 +6624,7 @@
"message": "Secrets Manager"
},
"secretsManagerAccessDescription": {
"message": "Activate user access to Secrets Manager."
"message": "Benutzerzugriff zum Secrets Manager aktivieren"
},
"userAccessSecretsManagerGA": {
"message": "Dieser Benutzer kann auf Secrets Manager zugreifen."
@@ -6831,17 +6828,25 @@
"trustedDeviceEncryption": {
"message": "Vertrauenswürdige Geräteverschlüsselung"
},
"memberDecryptionTdeDescriptionStart": {
"message": "Einmal authentifiziert, entschlüsseln Mitglieder Tresordaten mit einem Schlüssel auf ihrem Gerät. Die",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartOne": {
"message": "Once authenticated, members will decrypt vault data using a key stored on their device. The",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLink": {
"message": "Verwaltungsrichtlinie zur Kontowiederherstellung",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The account recovery administration policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionLinkOne": {
"message": "single organization",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionEnd": {
"message": "mit automatischer Registrierung wird aktiviert, wenn diese Option verwendet wird.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The master password reset policy with automatic enrollment will turn on when this option is used.'"
"memberDecryptionTdeDescriptionPartTwo": {
"message": "policy and ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionLinkTwo": {
"message": "account recovery administration",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"memberDecryptionTdeDescriptionPartThree": {
"message": "policy with automatic enrollment will turn on when this option is used.",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy and account recovery administration policy with automatic enrollment will turn on when this option is used.'"
},
"notFound": {
"message": "$RESOURCE$ nicht gefunden",
@@ -6859,18 +6864,18 @@
"message": "Der Benutzer hat ein Passwort aktualisiert, das durch die Kontowiederherstellung ausgestellt wurde."
},
"activatedAccessToSecretsManager": {
"message": "Activated access to Secrets Manager",
"message": "Zugriff zum Secrets Manager aktiviert",
"description": "Confirmation message that one or more users gained access to Secrets Manager"
},
"activateAccess": {
"message": "Activate access"
"message": "Zugriff aktivieren"
},
"bulkEnableSecretsManagerDescription": {
"message": "Den folgenden Mitgliedern Zugriff auf Secrets Manager gewähren. Die im Passwort-Manager zugewiesene Rolle wird auf Secrets Manager angewendet.",
"description": "This description is shown to an admin when they are attempting to add more users to Secrets Manager."
},
"activateSecretsManager": {
"message": "Activate Secrets Manager"
"message": "Secrets Manager aktivieren"
},
"yourOrganizationsFingerprint": {
"message": "Fingerabdruck-Phrase deiner Organisation",

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