masks-server 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/masks/server/manage_controller.rb +1 -0
  3. data/app/controllers/masks/server/scim/metadata_controller.rb +1 -1
  4. data/app/models/masks/server/app_preset.rb +1 -1
  5. data/app/models/masks/server/client.rb +24 -0
  6. data/app/views/masks/server/handshakes/show.html.erb +2 -8
  7. data/app/views/masks/server/logins/_consent.html.erb +43 -44
  8. data/app/views/masks/server/logins/_enrol.html.erb +1 -1
  9. data/app/views/masks/server/logins/_setup_configure.html.erb +2 -6
  10. data/app/views/masks/server/logins/_signup.html.erb +2 -9
  11. data/app/views/masks/server/logins/_signup_credentials.html.erb +1 -2
  12. data/app/views/masks/server/logins/_signup_head.html.erb +1 -11
  13. data/config/locales/de/account.yml +4 -4
  14. data/config/locales/de/handshakes.yml +6 -6
  15. data/config/locales/de/logins.yml +44 -30
  16. data/config/locales/en/account.yml +4 -4
  17. data/config/locales/en/handshakes.yml +6 -6
  18. data/config/locales/en/logins.yml +44 -30
  19. data/config/locales/es/account.yml +4 -4
  20. data/config/locales/es/handshakes.yml +6 -6
  21. data/config/locales/es/logins.yml +42 -28
  22. data/config/locales/fr/account.yml +4 -4
  23. data/config/locales/fr/handshakes.yml +6 -6
  24. data/config/locales/fr/logins.yml +43 -29
  25. data/lib/masks/server/schema_reference.rb +1 -1
  26. data/public/masks-assets/.vite/manifest.json +3 -3
  27. data/public/masks-assets/assets/app-Cfbt-A5V.css +2 -0
  28. data/public/masks-assets/assets/login-BDggujiZ.js +6 -0
  29. data/public/masks-assets/assets/login-BDggujiZ.js.map +1 -0
  30. data/public/masks-assets/assets/{manage-DpVxe5sv.js → manage-VgOqKj7N.js} +2 -2
  31. data/public/masks-assets/assets/manage-VgOqKj7N.js.map +1 -0
  32. data/version.txt +1 -1
  33. metadata +6 -6
  34. data/public/masks-assets/assets/app-BXOScMjL.css +0 -2
  35. data/public/masks-assets/assets/login-C21_jb6L.js +0 -4
  36. data/public/masks-assets/assets/login-C21_jb6L.js.map +0 -1
  37. data/public/masks-assets/assets/manage-DpVxe5sv.js.map +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c268c36afc7aa404d7cb904ef65cb1f67db51d6b84bdb3a5f83d5aae7d84bf48
4
- data.tar.gz: '09285b0606e241c323c82f16555328830421c7d97338d9aa32f38055e6972353'
3
+ metadata.gz: 475ac0de6cacc1cec932c465ef03e11e494cca4c53c2e4450a8bbd1299b07830
4
+ data.tar.gz: 305e006530de29f816aef4e49f6173ca18f524ad5a21631700bc09efbf463f98
5
5
  SHA512:
6
- metadata.gz: a253ac4a9e52258b001f1a7424a189728979a5363255d1d9c4d306e70385ea2eecdd8f93e2859603f6959e43786f90be43921d5ed7bc523fa81477f06384f507
7
- data.tar.gz: 844b3eb9927070dfddbea67dbbb17992772e84348c35ffdc9feba33fd1b079f718e9d986b8f9da591f77498a54a8404c7240a6dd5ad22d320a04500ec57641f6
6
+ metadata.gz: 2856b2e35e55cf7fb8724dcfd00e3007eaedf14ff49f8bce48b2936d8afc987dd13506c476e3d4efb1f492b5c25db557a73f37b9edb9efc60dcd3b4b30dd664b
7
+ data.tar.gz: c588ee7cd4211a8205e08cb8a2957448981c6c8ae34c1e0723987f06c7675cb380084564d09e2ee5ba596af6baf83476a484b5a3c5a84fadd575aecde8d33a6d
@@ -9,6 +9,7 @@ module Masks
9
9
  resource: issuer.manage_resource,
10
10
  graphql: manage_graphql_path,
11
11
  root: manage_path,
12
+ clientId: Client.console!(issuer).client_id,
12
13
  account: root_path,
13
14
  tenant: current_tenant.to_identity,
14
15
  copy: I18n.t("manage", default: {})
@@ -7,7 +7,7 @@ module Masks
7
7
  def service_provider_config
8
8
  scim({
9
9
  "schemas" => [ Scim::SERVICE_PROVIDER_CONFIG ],
10
- "documentationUri" => "#{::Rails.configuration.masks.docs_url}/guides/sso-saml/#provisioning",
10
+ "documentationUri" => "#{::Rails.configuration.masks.docs_url}/build/sso-saml/#provisioning",
11
11
  "patch" => { "supported" => true },
12
12
  "bulk" => { "supported" => false, "maxOperations" => 0, "maxPayloadSize" => 0 },
13
13
  "filter" => { "supported" => true, "maxResults" => Scim::MAX_RESULTS },
@@ -10,7 +10,7 @@ module Masks
10
10
  key: "proxy", name: "Any app behind Caddy, Traefik, or nginx", forward: true,
11
11
  redirects: [ "{base}/masks-auth/callback" ],
12
12
  scopes: %w[openid],
13
- guide: "https://masks.pages.dev/guides/forward-auth/",
13
+ guide: "https://masks.pages.dev/build/forward-auth/",
14
14
  settings: [
15
15
  [ "Caddy", "{host} {\n forward_auth {masks_origin} {\n uri /forward-auth\n header_up Host {masks_host}\n" \
16
16
  " copy_headers Remote-User Remote-Email Remote-Name Remote-Groups\n }\n reverse_proxy your-app:8080\n}" ],
@@ -101,6 +101,9 @@ module Masks
101
101
  belongs_to :enrolled_by, class_name: "Client", optional: true, inverse_of: :enrolled
102
102
  belongs_to :sign_in_policy, optional: true
103
103
 
104
+ CONSOLE_ID = "masks-manage".freeze
105
+ CONSOLE_SCOPES = [ Scopes::OPENID, Scopes::PROFILE, Scopes::EMAIL, Scopes::MANAGE, *ManageRoles::SCOPES ].uniq.freeze
106
+
104
107
  scope :approved, -> { where.not(approved_at: nil) }
105
108
  scope :speaking, ->(protocol) { active.where(protocol: protocol) }
106
109
 
@@ -113,6 +116,27 @@ module Masks
113
116
  LOOPBACK.include?(host) || host.end_with?(".localhost")
114
117
  end
115
118
 
119
+ def console!(issuer)
120
+ approved_for(issuer.manage_resource) || create!(
121
+ client_id: CONSOLE_ID,
122
+ name: "Manage #{Current.tenant.name}",
123
+ redirect_uris: [ "#{issuer.manage_resource}/callback" ],
124
+ post_logout_redirect_uris: [ issuer.manage_resource ],
125
+ resources: [ issuer.manage_resource ],
126
+ allowed_scopes: Scopes.join(CONSOLE_SCOPES),
127
+ grant_types: %w[authorization_code refresh_token],
128
+ response_types: [ "code" ],
129
+ token_endpoint_auth_method: "none",
130
+ client_uri: issuer.url,
131
+ handshake_return_to: issuer.manage_resource,
132
+ consent_required: false,
133
+ dynamic: false,
134
+ approved_at: Time.current
135
+ )
136
+ rescue ActiveRecord::RecordNotUnique
137
+ find_by!(client_id: CONSOLE_ID)
138
+ end
139
+
116
140
  def approve!(handshake, actor:)
117
141
  client = approved_for(handshake.resource) || new(client_id: SecureRandom.uuid)
118
142
 
@@ -12,21 +12,15 @@
12
12
  <% hot, rest = @scopes.to_a.partition { |scope, _| heeded_scope?(scope) } %>
13
13
  <% after_sign_out = @handshake.try(:post_logout_redirect_uri) %>
14
14
 
15
- <div class="auth-pair">
15
+ <div class="auth-solo">
16
16
  <span class="auth-mark auth-mark-client" aria-hidden="true"><%= name.to_s.first&.upcase %></span>
17
- <span class="auth-wire"></span>
18
- <%= tenant_mark(Masks::Server::Current.tenant) %>
19
17
  </div>
20
18
 
21
19
  <div class="prompt-head">
22
20
  <h1 class="prompt-title"><%= t(@existing ? ".title_again" : ".title", name: name, tenant: tenant) %></h1>
23
21
 
24
- <p class="handshake-origin">
25
- <span class="handshake-origin-label"><%= t(".runs_at") %></span>
26
- <span class="handshake-origin-value"><%= @handshake.origin %></span>
27
- </p>
28
-
29
22
  <p class="prompt-lede">
23
+ <%= t(".runs_at", name: name, origin: @handshake.origin) %>
30
24
  <%= t(@existing ? ".lede_again_html" : ".lede_html", name: name, tenant: tenant) %>
31
25
  </p>
32
26
  </div>
@@ -1,15 +1,14 @@
1
1
  <% state = login.state("consent") %>
2
2
  <% client = login.client_json || {} %>
3
3
  <% hot, rest = ranked_scopes(Masks::Server::ResourceMetadata.describe(state.audience, state.scopes)) %>
4
+ <% all = hot + rest %>
4
5
 
5
- <div class="auth-pair">
6
+ <div class="auth-solo">
6
7
  <% if client["logo"] %>
7
8
  <%= image_tag client["logo"], alt: "", class: "auth-mark auth-mark-client auth-mark-logo", referrerpolicy: "no-referrer" %>
8
9
  <% else %>
9
10
  <span class="auth-mark auth-mark-client" aria-hidden="true"><%= client["name"].to_s.strip.first&.upcase %></span>
10
11
  <% end %>
11
- <span class="auth-wire"></span>
12
- <%= tenant_mark(Masks::Server::Current.tenant) %>
13
12
  </div>
14
13
 
15
14
  <%= render "masks/server/logins/head", title: t(".title", client: login.client&.name) %>
@@ -20,48 +19,30 @@
20
19
  <div class="ledger-row">
21
20
  <span class="ledger-label"><%= t(".access") %></span>
22
21
 
23
- <% if hot.empty? && rest.empty? %>
22
+ <% if all.empty? %>
24
23
  <p class="empty"><%= t(".no_access") %></p>
24
+ <% else %>
25
+ <ul class="plain-list">
26
+ <% all.each do |_, description| %>
27
+ <li><%= description %></li>
28
+ <% end %>
29
+ </ul>
25
30
  <% end %>
26
-
27
- <ul class="grant-scopes">
28
- <% hot.each do |scope, description| %>
29
- <li class="grant-scope grant-scope-hot">
30
- <span><%= description %></span>
31
- <span class="chip-key"><%= scope %></span>
32
- </li>
33
- <% end %>
34
-
35
- <% if hot.any? && rest.any? %>
36
- <li class="grant-scope-split"></li>
37
- <% end %>
38
-
39
- <% rest.each do |scope, description| %>
40
- <li class="grant-scope">
41
- <span><%= description %></span>
42
- <span class="chip-key"><%= scope %></span>
43
- </li>
44
- <% end %>
45
- </ul>
46
31
  </div>
47
32
 
48
33
  <% if state.audience.any? %>
49
34
  <div class="ledger-row">
50
- <span class="ledger-label"><%= t(".audience") %></span>
51
- <% state.audience.each do |resource| %>
52
- <span class="ledger-value aside-mono"><%= resource %></span>
53
- <% end %>
35
+ <span class="aside"><%= t(".audience", resources: state.audience.join(", ")) %></span>
54
36
  </div>
55
37
  <% end %>
56
38
 
57
39
  <% if (details = state.details&.described).present? %>
58
40
  <div class="ledger-row">
59
41
  <span class="ledger-label"><%= t(".details") %></span>
60
- <ul class="grant-scopes">
42
+ <ul class="plain-list">
61
43
  <% details.each do |detail| %>
62
- <li class="grant-scope grant-scope-hot grant-detail">
63
- <span><%= detail["label"] %></span>
64
- <span class="chip-key"><%= detail["type"] %></span>
44
+ <li>
45
+ <%= detail["label"] %>
65
46
  <% if detail["fields"].any? %>
66
47
  <dl class="grant-fields">
67
48
  <% detail["fields"].each do |name, value| %>
@@ -75,23 +56,41 @@
75
56
  </ul>
76
57
  </div>
77
58
  <% end %>
59
+ </div>
78
60
 
79
- <% if client["returnsTo"] %>
61
+ <% links = { "site" => t(".site", client: client["name"]), "terms" => t(".terms"), "privacy" => t(".privacy") }.select { |key, _| client[key] } %>
62
+ <details class="disclosure handshake-more">
63
+ <summary class="textlink"><%= t(".more") %></summary>
64
+
65
+ <div class="slab">
80
66
  <div class="ledger-row">
81
- <span class="ledger-label"><%= t(".returns_to") %></span>
82
- <span class="ledger-value aside-mono"><%= client["returnsTo"] %></span>
67
+ <span class="ledger-label"><%= t(".scopes") %></span>
68
+ <ul class="grant-scopes">
69
+ <% all.each do |scope, description| %>
70
+ <li class="grant-scope">
71
+ <span><%= description %></span>
72
+ <span class="chip-key"><%= scope %></span>
73
+ </li>
74
+ <% end %>
75
+ </ul>
83
76
  </div>
84
- <% end %>
85
- </div>
86
77
 
87
- <% links = { "site" => t(".site", client: client["name"]), "terms" => t(".terms"), "privacy" => t(".privacy") }.select { |key, _| client[key] } %>
88
- <% if links.any? %>
89
- <p class="aside client-links">
90
- <% links.each do |key, label| %>
91
- <%= link_to label, client[key], class: "textlink", rel: "noopener noreferrer", target: "_blank" %>
78
+ <% if client["returnsTo"] %>
79
+ <div class="ledger-row">
80
+ <span class="ledger-label"><%= t(".returns_to") %></span>
81
+ <span class="ledger-value aside-mono"><%= client["returnsTo"] %></span>
82
+ </div>
92
83
  <% end %>
93
- </p>
94
- <% end %>
84
+
85
+ <% if links.any? %>
86
+ <p class="aside client-links">
87
+ <% links.each do |key, label| %>
88
+ <%= link_to label, client[key], class: "textlink", rel: "noopener noreferrer", target: "_blank" %>
89
+ <% end %>
90
+ </p>
91
+ <% end %>
92
+ </div>
93
+ </details>
95
94
 
96
95
  <div class="action-row">
97
96
  <%= form_with url: login_path, method: :post, id: "consent", class: "action-grow" do |form| %>
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div class="flow<%= " setup" if signing_up %>">
9
9
  <% if signing_up %>
10
- <%= render "masks/server/logins/signup_head", login: login, at: 2, mark: login.actor&.identifier.to_s %>
10
+ <%= render "masks/server/logins/signup_head", login: login, at: 2 %>
11
11
 
12
12
  <p class="aside"><%= enrolment["required"] ? t(".lede") : t(".lede_optional") %></p>
13
13
  <% else %>
@@ -1,7 +1,7 @@
1
1
  <% configure = login.state("configure").as_json["configure"] %>
2
2
 
3
3
  <div class="setup flow">
4
- <%= render "masks/server/logins/signup_head", login: login, at: 3, mark: login.actor&.identifier.to_s %>
4
+ <%= render "masks/server/logins/signup_head", login: login, at: 3 %>
5
5
 
6
6
  <%= form_with url: login_path, method: :post, id: "setup-configure", class: "flow" do |form| %>
7
7
  <%= hidden_field_tag :rid, login.rid %>
@@ -12,11 +12,6 @@
12
12
  <%= form.text_field :called, value: configure["called"], class: "control" %>
13
13
  <span class="field-hint"><%= t(".called_hint") %></span>
14
14
  </label>
15
-
16
- <div class="ledger-row">
17
- <span class="ledger-label"><%= t("logins.signing_up.origin") %></span>
18
- <span class="ledger-value aside-mono"><%= Masks::Server::Current.origin %></span>
19
- </div>
20
15
  </div>
21
16
 
22
17
  <button type="submit" name="event" value="setup-configure" class="action">
@@ -25,6 +20,7 @@
25
20
  <% end %>
26
21
 
27
22
  <p class="aside">
23
+ <%= t("logins.signing_up.origin", origin: Masks::Server::Current.origin) %>
28
24
  <%= t("logins.signing_up.once") %>
29
25
  <%= link_to t("logins.signing_up.docs"), Rails.configuration.masks.docs_url,
30
26
  class: "textlink", rel: "noopener", target: "_blank" %>
@@ -4,8 +4,7 @@
4
4
  <% done = ->(field) { " ledger-step-done" if value.(field).present? } %>
5
5
 
6
6
  <div class="setup flow">
7
- <%= render "masks/server/logins/signup_head", login: login, at: 1,
8
- mark: value.("nickname").presence || value.("email") %>
7
+ <%= render "masks/server/logins/signup_head", login: login, at: 1 %>
9
8
 
10
9
  <%= form_with url: login_path, method: :post, id: "signup", class: "flow" do |form| %>
11
10
  <%= hidden_field_tag :rid, login.rid %>
@@ -51,13 +50,6 @@
51
50
  <%= render "masks/server/logins/hint", login: login, field: "phone" %>
52
51
  </label>
53
52
  <% end %>
54
-
55
- <% if login.signing_up["firstRun"] %>
56
- <div class="ledger-row">
57
- <span class="ledger-label"><%= t("logins.signing_up.origin") %></span>
58
- <span class="ledger-value aside-mono"><%= Masks::Server::Current.origin %></span>
59
- </div>
60
- <% end %>
61
53
  </div>
62
54
 
63
55
  <% if signup["work"] %>
@@ -71,6 +63,7 @@
71
63
 
72
64
  <% if login.signing_up["firstRun"] %>
73
65
  <p class="aside">
66
+ <%= t("logins.signing_up.origin", origin: Masks::Server::Current.origin) %>
74
67
  <%= t("logins.signing_up.once") %>
75
68
  <%= link_to t("logins.signing_up.docs"), Rails.configuration.masks.docs_url,
76
69
  class: "textlink", rel: "noopener", target: "_blank" %>
@@ -2,8 +2,7 @@
2
2
  <% rows = %w[name nickname email phone].filter_map { |field| [ field, signup[field] ] if signup[field].present? } %>
3
3
 
4
4
  <div class="setup flow">
5
- <%= render "masks/server/logins/signup_head", login: login, at: 2,
6
- mark: signup["nickname"].presence || signup["email"] %>
5
+ <%= render "masks/server/logins/signup_head", login: login, at: 2 %>
7
6
 
8
7
  <%= form_with url: login_path, method: :post, id: "signup-credentials", class: "flow" do |form| %>
9
8
  <%= hidden_field_tag :rid, login.rid %>
@@ -1,20 +1,10 @@
1
1
  <% tenant = Masks::Server::Current.tenant&.name.to_s %>
2
2
  <% signing_up = login.signing_up %>
3
3
 
4
- <div class="auth-pair">
5
- <span class="auth-mark auth-mark-client<%= " auth-mark-pending" if mark.blank? %>" aria-hidden="true"><%= mark.to_s.first&.upcase %></span>
6
- <span class="auth-wire"></span>
7
- <% if signing_up["firstRun"] %>
8
- <img src="/masks-public/icon.svg" alt="" class="auth-mark auth-mark-rose">
9
- <% else %>
10
- <%= tenant_mark(Masks::Server::Current.tenant) %>
11
- <% end %>
12
- </div>
13
-
14
4
  <% if signing_up["firstRun"] %>
15
5
  <%= render "masks/server/logins/head", cap: t("logins.signing_up.setup_cap"), title: t("logins.signing_up.setup_title"), name: tenant %>
16
6
  <% else %>
17
- <%= render "masks/server/logins/head", title: t("logins.signing_up.signup_title"), name: tenant %>
7
+ <%= render "masks/server/logins/head", title: t("logins.signing_up.signup_title") %>
18
8
  <% end %>
19
9
 
20
10
  <%= render "masks/server/logins/steps", steps: signing_up["steps"], at: local_assigns[:at] || signing_up["steps"].length %>
@@ -62,7 +62,7 @@ de:
62
62
  set:
63
63
  one: "1 eingerichtet"
64
64
  other: "%{count} eingerichtet"
65
- explained: "Statt ein Passwort einzugeben, prüft Ihr Gerät auf dieselbe Weise, wie es sich entsperrt, dass Sie es sind. Das zählt als beide Faktoren zugleich, daher müssen Sie auf keinen Code warten."
65
+ explained: "Statt ein Passwort einzutippen, prüft Ihr Gerät so, dass Sie es sind, wie es sich ohnehin entsperrt. Es zählt auch als Ihr zweiter Schritt, also müssen Sie auf keinen Code warten."
66
66
  used: "zuletzt verwendet vor %{age}"
67
67
  never_used: "nie verwendet"
68
68
  remove: "Entfernen"
@@ -209,11 +209,11 @@ de:
209
209
  remembered: "%{label}, ohne Nachfrage bis %{date}"
210
210
  heading: "Apps, die Sie zugelassen haben"
211
211
  none_yet: "Bisher hat nichts angefragt. Eine App erscheint hier, sobald Sie sich bei ihr anmelden, zusammen mit dem, was sie sehen darf."
212
- revoke: "Zugriff widerrufen"
212
+ revoke: "Zugriff entfernen"
213
213
  more:
214
214
  one: "und eine weitere"
215
215
  other: "und %{count} weitere"
216
- confirm_revoke: "%{client} widerrufen? Alles, was die App hält, funktioniert nicht mehr, und sie muss bei Ihrer nächsten Anmeldung erneut fragen."
216
+ confirm_revoke: "%{client} den Zugriff entfernen? Alles, was es gerade hält, funktioniert nicht mehr, und es muss bei der nächsten Anmeldung erneut fragen."
217
217
 
218
218
  connections:
219
219
  heading: "Verbundene Konten"
@@ -258,7 +258,7 @@ de:
258
258
 
259
259
  export:
260
260
  heading: "Ihr Konto herunterladen"
261
- state: "JSON"
261
+ state: "Eine Datei"
262
262
  lede: "Eine Datei mit Ihrem Profil, Ihren Anmeldemethoden, Organisationen, Apps, verbundenen Konten und Geräten sowie der Aktivität, die masks aufbewahrt hat. Sie enthält keine Passwörter, Codes oder Schlüssel."
263
263
  again: "Ihre Anmeldung ist eine Weile her, daher werden Sie zuerst gebeten, sich erneut anzumelden."
264
264
  submit: "Herunterladen"
@@ -3,29 +3,29 @@ de:
3
3
  show:
4
4
  page_title: "%{name} verbinden"
5
5
  page_title_again: "%{name} neu verbinden"
6
- title: "%{name} mit %{tenant} verbinden?"
6
+ title: "%{name} verbinden?"
7
7
  title_again: "%{name} neu verbinden?"
8
- runs_at: "Läuft unter"
8
+ runs_at: "%{name} läuft unter %{origin}."
9
9
  lede_html: "Alle können sich dann mit ihrem %{tenant}-Konto bei <strong>%{name}</strong> anmelden. Vorerst haben nur Sie Zugang, und Sie legen später fest, wer noch hinein darf."
10
10
  lede_again_html: "<strong>%{name}</strong> ist bereits mit %{tenant} verbunden. Beim neuen Verbinden wird die App neu eingerichtet. Vorerst haben nur Sie Zugang, und Sie legen später fest, wer noch hinein darf."
11
11
  stops_working: "Die bisherige Verbindung zu %{name} funktioniert dann nicht mehr."
12
12
  connected_by_you: "Sie haben %{name} am %{date} verbunden."
13
13
  connected_by: "%{who} hat %{name} am %{date} verbunden."
14
- signed_in_as: "Sie stimmen zu als"
14
+ signed_in_as: "Sie verbinden als"
15
15
  unconfirmed: "(E-Mail noch nicht bestätigt)"
16
- check: "Sehen Sie sich das zuerst an"
16
+ check: "Bevor Sie verbinden"
17
17
  heed:
18
18
  offline_access: "%{name} kann Personen angemeldet halten, ohne erneut zu fragen, bis sie sich abmelden."
19
19
  delegates_title: "Personen bitten, ihre anderen Konten zu verbinden"
20
20
  delegates: "Jede Person entscheidet selbst. %{name} kann diese Konten dann nutzen, während sie nicht da sind."
21
21
  delegate: "%{name} kann dieses Konto nutzen, während Sie nicht da sind, bis Sie es beenden."
22
22
  manage: "Alle, die sich über %{name} anmelden, können jede Einstellung auf diesem Server ändern."
23
- sees: "%{name} sieht"
23
+ sees: "%{name} erfährt"
24
24
  area: "Eigene Berechtigungen von %{name}"
25
25
  area_says_html: "%{name} erhält eigene Berechtigungen mit dem Namen %{namespaces}. Sie entscheiden, wer sie bekommt."
26
26
  area_yours: " Sie erhalten sie jetzt alle."
27
27
  also: "%{name} kann außerdem"
28
- details: "Technische Details"
28
+ details: "Details"
29
29
  scopes: "Scopes"
30
30
  client: "Zugangsdaten"
31
31
  credentials:
@@ -16,7 +16,7 @@ de:
16
16
  name: "Name"
17
17
  phone: "Telefon"
18
18
  password: "Passwort"
19
- not_you: "Nicht Sie?"
19
+ not_you: "Ein anderes Konto verwenden"
20
20
  sign_out: "Abmelden"
21
21
  use_passkey: "Passkey verwenden"
22
22
  or: "oder"
@@ -40,10 +40,12 @@ de:
40
40
  tab_confirmation: "Bestätigung"
41
41
  setup_cap: "Willkommen!"
42
42
  setup_title: "Einrichten"
43
- signup_title: "Konto erstellen bei"
43
+ signup_title: "Konto anlegen"
44
44
  token: "Einrichtungstoken"
45
- token_hint: "Steht in den Server-Logs, die nur lesen kann, wer masks betreibt."
46
- origin: "Einrichten unter"
45
+ token_hint: "Es steht im Protokoll des Servers."
46
+ origin: "Dieses masks antwortet unter %{origin}."
47
+ pick_nickname: "Einen Spitznamen wählen"
48
+ nickname_hint: "Andere sehen ihn. Lassen Sie es, wie es ist, um %{suggested} zu verwenden."
47
49
  once: "Dieser Bildschirm erscheint nicht wieder."
48
50
  docs: "Dokumentation lesen."
49
51
  confirm: "Passwort bestätigen"
@@ -57,15 +59,15 @@ de:
57
59
  proving: "Browser wird geprüft"
58
60
 
59
61
  identify:
60
- heading: "Melden Sie sich an, um fortzufahren"
62
+ heading: "Anmelden"
61
63
  heading_to: "Bei %{client} anmelden"
62
- identifier: "Spitzname oder E-Mail-Adresse"
63
- signup_hint: "Neu hier? Geben Sie die Adresse ein, die Sie verwenden möchten, und dafür wird ein Konto erstellt."
64
+ identifier: "E-Mail oder Spitzname"
65
+ signup_hint: "Neu hier? Geben Sie Ihre E-Mail-Adresse ein, und masks legt ein Konto für Sie an."
64
66
 
65
67
  first_factor:
66
68
  title: "Geben Sie Ihr Passwort ein"
67
69
  title_code: "Mit einem Code anmelden"
68
- forgot: "Vergessen?"
70
+ forgot: "Passwort vergessen?"
69
71
  email_me: "Stattdessen einen Code per E-Mail senden"
70
72
  email_only: "Code per E-Mail senden"
71
73
 
@@ -76,16 +78,16 @@ de:
76
78
  sent_again: "Gesendet"
77
79
 
78
80
  second_factor:
79
- title: "Geben Sie Ihren Code ein"
80
- title_passkey: "Verwenden Sie Ihren zweiten Faktor"
81
- trust: "Diesem Gerät %{duration} lang vertrauen"
81
+ title: "Bestätigen Sie, dass Sie es sind"
82
+ title_passkey: "Bestätigen Sie mit Ihrem Passkey, dass Sie es sind"
83
+ trust: "Auf diesem Gerät %{duration} lang überspringen"
82
84
  use_backup_code: "Backup-Code verwenden"
83
85
  stuck_insecure: "Der zweite Faktor dieses Kontos ist ein Passkey, und der Browser bietet Passkeys nur Seiten an, die über HTTPS ausgeliefert werden. Öffnen Sie diese Seite über HTTPS, um fortzufahren."
84
86
  stuck_unsupported: "Der zweite Faktor dieses Kontos ist ein Passkey, und dieser Browser unterstützt keine Passkeys. Öffnen Sie diese Seite in einem Browser, der sie unterstützt, um fortzufahren."
85
87
  stuck_no_script: "Der zweite Faktor dieses Kontos ist ein Passkey, und ein Passkey braucht JavaScript. Aktivieren Sie JavaScript, um fortzufahren."
86
88
  stuck_inbox: "Diese Anmeldung hat in Ihrem Posteingang begonnen, daher kann ein dorthin gesendeter Code sie nicht bestätigen. Beginnen Sie von vorn und melden Sie sich mit Ihrem Passwort an, um einen Code per E-Mail zu verwenden."
87
89
  stuck_nothing: "Dieses Konto hat keinen zweiten Faktor, den diese Anmeldung verwenden kann. Ein Verwalter kann ihn zurücksetzen."
88
- recovery_request: "Ich kann nichts davon verwenden"
90
+ recovery_request: "Ich kann keinen davon verwenden"
89
91
  recovery_ask: "Einen Verwalter um Hilfe bitten"
90
92
  recovery_requested: "Ein Verwalter wurde gebeten, Ihre zweiten Faktoren zurückzusetzen. Er wird Sie möglicherweise kontaktieren, um sicherzugehen, dass Sie es sind. Danach melden Sie sich erneut an, um einen neuen einzurichten."
91
93
  sent_to: "Gesendet an %{to}."
@@ -101,16 +103,26 @@ de:
101
103
  approval_checked: "Ich habe genehmigt"
102
104
 
103
105
  enrol:
104
- title: "Sichern Sie Ihr Konto"
105
- lede: "Fügen Sie beliebig viele zweite Faktoren hinzu. Dieses Konto braucht mindestens einen."
106
- lede_optional: "Fügen Sie beliebig viele zweite Faktoren hinzu."
106
+ title: "Konto schützen"
107
+ lede: "Wählen Sie einen Weg, mit dem Sie bei der Anmeldung bestätigen, dass Sie es sind. Weitere können Sie später hinzufügen."
108
+ lede_optional: "Wählen Sie einen Weg, mit dem Sie bei der Anmeldung bestätigen, dass Sie es sind, oder überspringen Sie das vorerst."
109
+ on_title: "Ihr Konto ist geschützt"
110
+ on_lede: "So bestätigen Sie bei der Anmeldung, dass Sie es sind."
111
+ on_label: "Eingeschaltet"
112
+ passkey: "Passkey"
107
113
  otp: "Authenticator-App"
114
+ otp_about: "Eine App wie Google Authenticator oder 1Password zeigt einen sechsstelligen Code."
108
115
  otp_on: "Aktiv"
109
- scan_hint: "Scannen Sie ihn, oder geben Sie diesen Schlüssel von Hand ein:"
116
+ scan_hint: "Scannen Sie das mit Ihrer Authenticator-App, oder tippen Sie den Schlüssel dort ein:"
117
+ passkey_about: "Ihr Telefon oder Computer prüft mit Gesicht, Fingerabdruck oder PIN, dass Sie es sind."
118
+ codes_email_about: "Bei jeder Anmeldung geht ein Code an %{to}."
119
+ codes_sms_about: "Bei jeder Anmeldung geht ein Code per SMS an %{to}."
120
+ another_way: "Einen anderen Weg wählen"
121
+ add_way: "Einen weiteren Weg hinzufügen"
110
122
  open: "In Ihrer Authenticator-App öffnen"
111
123
  turn_on: "Aktivieren"
112
124
  passkeys: "Passkeys"
113
- passkeys_none: "Noch keine. Einer, der eine PIN oder einen Fingerabdruck prüft, zählt."
125
+ passkeys_none: "Noch keiner."
114
126
  passkeys_some: "%{count} hinzugefügt"
115
127
  add_passkey: "Passkey hinzufügen"
116
128
  add_another_passkey: "Weiteren hinzufügen"
@@ -118,17 +130,17 @@ de:
118
130
  codes_email_hint: "Ein an %{to} gesendeter Code bestätigt jede Anmeldung."
119
131
  codes_sms: "Codes per SMS"
120
132
  codes_sms_hint: "Ein per SMS an %{to} gesendeter Code bestätigt jede Anmeldung."
121
- send_code: "Code senden, um es zu aktivieren"
133
+ send_code: "Code schicken"
122
134
  sent_to: "Gesendet an %{to}."
123
135
  backup_codes: "Backup-Codes"
124
- backup_codes_waiting: "Werden für Sie erstellt, sobald oben ein Faktor aktiv ist."
125
- backup_codes_hint: "Jeder meldet einmal an, wenn nichts anderes zur Hand ist. Sie werden nicht erneut angezeigt."
136
+ backup_codes_waiting: "Werden erstellt, sobald ein Weg oben eingeschaltet ist."
137
+ backup_codes_hint: "Jeder Code meldet Sie einmal an, falls Sie Ihren anderen Weg verlieren. Sichern Sie sie jetzt. Sie werden nicht noch einmal gezeigt."
126
138
  backup_codes_left: "%{count} übrig"
127
139
  backup_codes_file: "Backup-Codes für %{account} bei %{origin}"
128
140
  copy: "Kopieren"
129
141
  copied: "Kopiert"
130
142
  download: "Herunterladen"
131
- kept: "Ich habe meine Backup-Codes sicher aufbewahrt"
143
+ kept: "Ich habe meine Backup-Codes gesichert"
132
144
  done: "Weiter"
133
145
  skip: "Vorerst überspringen"
134
146
 
@@ -163,7 +175,7 @@ de:
163
175
  prove_email:
164
176
  title: "Prüfen Sie Ihre E-Mails"
165
177
  lede: "Ein sechsstelliger Code ist unterwegs an %{email}. Geben Sie ihn ein, um fortzufahren."
166
- no_mailer: "Dieser Server kann noch keine E-Mails senden, daher kann keine Adresse zur Anmeldung verwendet werden. Verwenden Sie Ihren Spitznamen oder wenden Sie sich an einen Verwalter."
178
+ no_mailer: "Dieser Server kann noch keine E-Mails senden, also kann er Ihre Adresse nicht prüfen. Melden Sie sich mit Ihrem Spitznamen an, oder bitten Sie den Betreiber, die Adresse für Sie zu bestätigen."
167
179
 
168
180
  setup_configure:
169
181
  called: "Dieser Server heißt"
@@ -202,17 +214,19 @@ de:
202
214
  as: "%{organization}, als %{role}"
203
215
 
204
216
  consent:
205
- title: "%{client} erlauben?"
206
- access: "Zugriff"
207
- no_access: "Nichts außer der Bestätigung, wer Sie sind."
208
- audience: "In Ihrem Namen bei"
217
+ title: "%{client} möchte Sie anmelden"
218
+ access: "Es erfährt"
219
+ no_access: "Nur, dass Sie hier ein Konto haben."
220
+ audience: "Es kann für Sie handeln bei %{resources}."
209
221
  details: "Genau dies"
210
222
  returns_to: "Danach zurück zu"
223
+ more: "Details"
224
+ scopes: "Berechtigungen"
211
225
  site: "Über %{client}"
212
226
  terms: "Nutzungsbedingungen"
213
227
  privacy: "Datenschutzerklärung"
214
228
  allow: "Erlauben"
215
- deny: "Ablehnen"
229
+ deny: "Jetzt nicht"
216
230
  working: "Wird erlaubt"
217
231
 
218
232
  settled:
@@ -221,7 +235,7 @@ de:
221
235
  waiting: "Sie werden zurückgeleitet"
222
236
 
223
237
  warnings:
224
- invalid-credentials: "Spitzname und Passwort passen nicht zusammen."
238
+ invalid-credentials: "Diese E-Mail oder dieser Spitzname und das Passwort passen nicht zusammen."
225
239
  invalid-code: "Dieser Code ist ungültig."
226
240
  invalid-backup-code: "Dieser Backup-Code ist ungültig."
227
241
  invalid-passkey: "Dieser Passkey konnte nicht verwendet werden."
@@ -233,7 +247,7 @@ de:
233
247
  passkey-crowded: "Dieses Konto hat bereits so viele Passkeys, wie dieser Server speichert."
234
248
  second-factor-required: "Aktivieren Sie mindestens einen zweiten Faktor, um fortzufahren."
235
249
  backup-codes-unkept: "Bewahren Sie Ihre Backup-Codes auf, bevor Sie fortfahren."
236
- missing-identifier: "Geben Sie Ihren Spitznamen oder Ihre E-Mail-Adresse ein."
250
+ missing-identifier: "Geben Sie Ihre E-Mail oder Ihren Spitznamen ein."
237
251
  missing-first-factor: "Dieser Schritt ist abgelaufen. Beginnen Sie von vorn."
238
252
  too-many-attempts: "Zu viele Versuche. Warten Sie einige Minuten."
239
253
  too-many-attempts-for-account: "Zu viele Versuche für dieses Konto."
@@ -258,7 +272,7 @@ de:
258
272
  work-unsolved: "Dieser Browser hat die Prüfung gegen automatisierte Registrierungen nicht abgeschlossen. Versuchen Sie es erneut."
259
273
  invitation-expired: "Diese Einladung ist nicht mehr gültig. Fordern Sie eine neue an."
260
274
  reset-expired: "Dieser Link zum Zurücksetzen ist nicht mehr gültig. Fordern Sie einen neuen an."
261
- no-mailer: "Dieser Server kann keine E-Mails senden. Wenden Sie sich an einen Verwalter."
275
+ no-mailer: "Dieser Server kann noch keine E-Mails senden, also kann er Ihr Passwort nicht zurücksetzen. Bitten Sie den Betreiber um einen Link zum Zurücksetzen."
262
276
  sso-failed: "Diese Anmeldung wurde nicht abgeschlossen. Versuchen Sie es erneut."
263
277
  sso-expired: "Diese Anmeldung hat zu lange gedauert. Versuchen Sie es erneut."
264
278
  sso-unavailable: "Diese Art der Anmeldung ist nicht verfügbar."
@@ -62,7 +62,7 @@ en:
62
62
  set:
63
63
  one: "1 set up"
64
64
  other: "%{count} set up"
65
- explained: "Instead of typing a password, your device checks it is you the way it already unlocks. It counts as both factors at once, so there is no code to wait for."
65
+ explained: "Instead of typing a password, your device checks it is you the way it already unlocks. It also counts as your second step, so there is no code to wait for."
66
66
  used: "last used %{age} ago"
67
67
  never_used: "never used"
68
68
  remove: "Remove"
@@ -209,11 +209,11 @@ en:
209
209
  remembered: "%{label}, without asking until %{date}"
210
210
  heading: "Apps you have let in"
211
211
  none_yet: "Nothing has asked yet. An app appears here once you sign in to it, with what you agreed it may see."
212
- revoke: "Revoke access"
212
+ revoke: "Remove access"
213
213
  more:
214
214
  one: "and one more"
215
215
  other: "and %{count} more"
216
- confirm_revoke: "Revoke %{client}? Anything it is holding stops working, and it has to ask again the next time you sign in."
216
+ confirm_revoke: "Remove %{client}'s access? Anything it is holding stops working, and it has to ask again the next time you sign in."
217
217
 
218
218
  connections:
219
219
  heading: "Connected accounts"
@@ -258,7 +258,7 @@ en:
258
258
 
259
259
  export:
260
260
  heading: "Download your account"
261
- state: "JSON"
261
+ state: "A file"
262
262
  lede: "A file with your profile, how you sign in, your organizations, apps, connected accounts, and devices, and the activity masks has kept. It holds no passwords, codes, or keys."
263
263
  again: "You signed in a while ago, so you will be asked to sign in again first."
264
264
  submit: "Download"