activeadmin-device_authorization 0.1.3
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +25 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +23 -0
- data/GOVERNANCE.md +25 -0
- data/LICENSE.md +21 -0
- data/README.md +162 -0
- data/SECURITY.md +25 -0
- data/activeadmin-device_authorization.gemspec +62 -0
- data/app/controllers/active_admin/device_authorization/application_controller.rb +9 -0
- data/app/controllers/active_admin/device_authorization/consents_controller.rb +83 -0
- data/app/controllers/active_admin/device_authorization/device_authorizations_controller.rb +51 -0
- data/app/controllers/active_admin/device_authorization/json_response.rb +25 -0
- data/app/controllers/active_admin/device_authorization/tokens_controller.rb +39 -0
- data/app/views/active_admin/device_authorization/_consent.html.erb +111 -0
- data/app/views/active_admin/device_authorization/_enter_code.html.erb +12 -0
- data/app/views/active_admin/device_authorization/_standalone_styles.html.erb +147 -0
- data/app/views/active_admin/device_authorization/consents/index.html.erb +19 -0
- data/app/views/active_admin/device_authorization/consents/show.html.erb +14 -0
- data/config/locales/en.yml +29 -0
- data/config/locales/fi.yml +29 -0
- data/config/locales/sv.yml +29 -0
- data/config/polyrun_coverage.yml +8 -0
- data/lib/active_admin/device_authorization/access_token_expiry.rb +46 -0
- data/lib/active_admin/device_authorization/callback.rb +15 -0
- data/lib/active_admin/device_authorization/configuration.rb +229 -0
- data/lib/active_admin/device_authorization/consent.rb +65 -0
- data/lib/active_admin/device_authorization/device_authorization_request.rb +70 -0
- data/lib/active_admin/device_authorization/engine.rb +17 -0
- data/lib/active_admin/device_authorization/page.rb +126 -0
- data/lib/active_admin/device_authorization/retention.rb +39 -0
- data/lib/active_admin/device_authorization/routes.rb +60 -0
- data/lib/active_admin/device_authorization/token_exchange.rb +144 -0
- data/lib/active_admin/device_authorization/user_code.rb +48 -0
- data/lib/active_admin/device_authorization/version.rb +7 -0
- data/lib/active_admin/device_authorization.rb +41 -0
- data/lib/activeadmin-device_authorization.rb +3 -0
- data/lib/tasks/active_admin_device_authorization.rake +10 -0
- data/sig/active_admin/device_authorization.rbs +5 -0
- metadata +296 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<% config = ActiveAdmin::DeviceAuthorization.config %>
|
|
2
|
+
<% available_scopes = grant.requested_scopes %>
|
|
3
|
+
<% default_scopes = Array(config.default_scopes).map(&:to_s) & available_scopes %>
|
|
4
|
+
<% absolute_ttl_choices = Array(config.access_token_absolute_ttl_choices) %>
|
|
5
|
+
<% client = grant.public_send(config.client_class_name.underscore) %>
|
|
6
|
+
<% heading_level = local_assigns.fetch(:heading_level, :h3) %>
|
|
7
|
+
<style>
|
|
8
|
+
.device-auth-user-code {
|
|
9
|
+
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;
|
|
10
|
+
font-size: 1.1em;
|
|
11
|
+
letter-spacing: 0.08em;
|
|
12
|
+
}
|
|
13
|
+
.device-auth-actions ol {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: 0.65rem;
|
|
17
|
+
list-style: none;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
}
|
|
21
|
+
@media (min-width: 40rem) {
|
|
22
|
+
.device-auth-actions ol {
|
|
23
|
+
flex-direction: row;
|
|
24
|
+
flex-wrap: wrap;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
|
|
29
|
+
<div class="panel">
|
|
30
|
+
<%= content_tag heading_level, t("active_admin.device_authorization.title"), class: "panel-title" %>
|
|
31
|
+
<div class="panel-body">
|
|
32
|
+
<p><%= t("active_admin.device_authorization.intro") %></p>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="panel">
|
|
37
|
+
<div class="panel-body">
|
|
38
|
+
<table class="attributes_table">
|
|
39
|
+
<tbody>
|
|
40
|
+
<tr>
|
|
41
|
+
<th scope="row"><%= t("active_admin.device_authorization.client") %></th>
|
|
42
|
+
<td><%= client.name %></td>
|
|
43
|
+
</tr>
|
|
44
|
+
<tr>
|
|
45
|
+
<th scope="row"><%= t("active_admin.device_authorization.user_code") %></th>
|
|
46
|
+
<td><code class="device-auth-user-code"><%= grant.user_code %></code></td>
|
|
47
|
+
</tr>
|
|
48
|
+
<tr>
|
|
49
|
+
<th scope="row"><%= t("active_admin.device_authorization.status") %></th>
|
|
50
|
+
<td><%= grant.status %></td>
|
|
51
|
+
</tr>
|
|
52
|
+
</tbody>
|
|
53
|
+
</table>
|
|
54
|
+
|
|
55
|
+
<div class="flash flash_alert" role="status">
|
|
56
|
+
<%= t("active_admin.device_authorization.verify_code") %>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<% if config.idle_expiry_enabled? %>
|
|
60
|
+
<p class="inline-hints"><%= t("active_admin.device_authorization.idle_note", idle_hours: (config.access_token_idle_ttl.to_i / 3600.0).round(1)) %></p>
|
|
61
|
+
<% end %>
|
|
62
|
+
|
|
63
|
+
<% if grant.pending? %>
|
|
64
|
+
<%= form_with url: send(:"#{config.path_namespace}_approve_device_auth_path", grant.user_code), method: :post, id: "device-auth-approve", data: {turbo: false}, class: "formtastic" do %>
|
|
65
|
+
<% if available_scopes.any? %>
|
|
66
|
+
<fieldset class="inputs">
|
|
67
|
+
<legend><%= t("active_admin.device_authorization.scopes") %></legend>
|
|
68
|
+
<p class="inline-hints"><%= t("active_admin.device_authorization.scopes_hint") %></p>
|
|
69
|
+
<% available_scopes.each do |scope| %>
|
|
70
|
+
<% field_id = "scope_#{scope.tr(":", "_")}" %>
|
|
71
|
+
<li class="choice">
|
|
72
|
+
<label for="<%= field_id %>">
|
|
73
|
+
<%= check_box_tag "scopes[]", scope, default_scopes.include?(scope), id: field_id %>
|
|
74
|
+
<%= config.label_for_scope(scope) %>
|
|
75
|
+
</label>
|
|
76
|
+
</li>
|
|
77
|
+
<% end %>
|
|
78
|
+
</fieldset>
|
|
79
|
+
<% end %>
|
|
80
|
+
<% if config.absolute_expiry_enabled? && absolute_ttl_choices.any? %>
|
|
81
|
+
<fieldset class="inputs">
|
|
82
|
+
<div class="input select">
|
|
83
|
+
<label class="label" for="absolute_ttl_seconds"><%= t("active_admin.device_authorization.absolute_ttl") %></label>
|
|
84
|
+
<%= select_tag :absolute_ttl_seconds,
|
|
85
|
+
options_for_select(
|
|
86
|
+
absolute_ttl_choices.map { |seconds| ["#{seconds.to_i / 3600} h", seconds.to_i] },
|
|
87
|
+
config.access_token_default_absolute_ttl.to_i
|
|
88
|
+
),
|
|
89
|
+
id: "absolute_ttl_seconds" %>
|
|
90
|
+
</div>
|
|
91
|
+
</fieldset>
|
|
92
|
+
<% end %>
|
|
93
|
+
<% end %>
|
|
94
|
+
|
|
95
|
+
<fieldset class="actions device-auth-actions">
|
|
96
|
+
<ol>
|
|
97
|
+
<li class="action input_action">
|
|
98
|
+
<%= submit_tag t("active_admin.device_authorization.approve"), form: "device-auth-approve" %>
|
|
99
|
+
</li>
|
|
100
|
+
<li class="action input_action">
|
|
101
|
+
<%= form_with url: send(:"#{config.path_namespace}_deny_device_auth_path", grant.user_code), method: :post, data: {turbo: false} do %>
|
|
102
|
+
<%= submit_tag t("active_admin.device_authorization.deny") %>
|
|
103
|
+
<% end %>
|
|
104
|
+
</li>
|
|
105
|
+
</ol>
|
|
106
|
+
</fieldset>
|
|
107
|
+
<% else %>
|
|
108
|
+
<p><%= t("active_admin.device_authorization.not_actionable", status: grant.status) %></p>
|
|
109
|
+
<% end %>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<p class="inline-hints"><%= t("active_admin.device_authorization.enter_code_hint") %></p>
|
|
2
|
+
<%= form_with url: send(:"#{ActiveAdmin::DeviceAuthorization.config.path_namespace}_device_auth_path"), method: :get, local: true, class: "formtastic" do %>
|
|
3
|
+
<fieldset class="inputs">
|
|
4
|
+
<div class="input string required">
|
|
5
|
+
<label class="label" for="user_code"><%= t("active_admin.device_authorization.user_code") %></label>
|
|
6
|
+
<%= text_field_tag :user_code, params[:user_code], id: "user_code", required: true, autocomplete: "off", autofocus: true %>
|
|
7
|
+
</div>
|
|
8
|
+
</fieldset>
|
|
9
|
+
<fieldset class="actions">
|
|
10
|
+
<%= submit_tag t("active_admin.device_authorization.continue") %>
|
|
11
|
+
</fieldset>
|
|
12
|
+
<% end %>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
.device-auth-standalone {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
color: #1a1a1a;
|
|
5
|
+
font-family: Georgia, "Times New Roman", serif;
|
|
6
|
+
line-height: 1.5;
|
|
7
|
+
margin: 0 auto;
|
|
8
|
+
max-width: 40rem;
|
|
9
|
+
padding: 1.5rem 1rem 3rem;
|
|
10
|
+
}
|
|
11
|
+
.device-auth-standalone *,
|
|
12
|
+
.device-auth-standalone *::before,
|
|
13
|
+
.device-auth-standalone *::after {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
.device-auth-standalone h1,
|
|
17
|
+
.device-auth-standalone .panel-title {
|
|
18
|
+
color: #111;
|
|
19
|
+
font-family: Georgia, "Times New Roman", serif;
|
|
20
|
+
font-size: 1.75rem;
|
|
21
|
+
font-weight: 700;
|
|
22
|
+
line-height: 1.25;
|
|
23
|
+
margin: 0 0 1rem;
|
|
24
|
+
}
|
|
25
|
+
.device-auth-standalone .panel {
|
|
26
|
+
background: #fff;
|
|
27
|
+
border: 1px solid #c8c8c8;
|
|
28
|
+
margin: 0 0 1.25rem;
|
|
29
|
+
padding: 1rem 1.1rem;
|
|
30
|
+
}
|
|
31
|
+
.device-auth-standalone .panel-body > *:first-child {
|
|
32
|
+
margin-top: 0;
|
|
33
|
+
}
|
|
34
|
+
.device-auth-standalone .panel-body > *:last-child {
|
|
35
|
+
margin-bottom: 0;
|
|
36
|
+
}
|
|
37
|
+
.device-auth-standalone .attributes_table {
|
|
38
|
+
border-collapse: collapse;
|
|
39
|
+
margin: 0 0 1rem;
|
|
40
|
+
width: 100%;
|
|
41
|
+
}
|
|
42
|
+
.device-auth-standalone .attributes_table th,
|
|
43
|
+
.device-auth-standalone .attributes_table td {
|
|
44
|
+
border-bottom: 1px solid #ddd;
|
|
45
|
+
padding: 0.55rem 0.35rem;
|
|
46
|
+
text-align: left;
|
|
47
|
+
vertical-align: top;
|
|
48
|
+
}
|
|
49
|
+
.device-auth-standalone .attributes_table th {
|
|
50
|
+
color: #444;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
width: 8.5rem;
|
|
53
|
+
}
|
|
54
|
+
.device-auth-standalone .device-auth-user-code {
|
|
55
|
+
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;
|
|
56
|
+
font-size: 1.15rem;
|
|
57
|
+
letter-spacing: 0.08em;
|
|
58
|
+
}
|
|
59
|
+
.device-auth-standalone .flash {
|
|
60
|
+
border: 1px solid #8a2f1d;
|
|
61
|
+
border-radius: 2px;
|
|
62
|
+
margin: 0 0 1rem;
|
|
63
|
+
padding: 0.75rem 0.9rem;
|
|
64
|
+
}
|
|
65
|
+
.device-auth-standalone .flash_alert {
|
|
66
|
+
background: #f8e8e4;
|
|
67
|
+
color: #5c1f14;
|
|
68
|
+
}
|
|
69
|
+
.device-auth-standalone .inline-hints {
|
|
70
|
+
color: #555;
|
|
71
|
+
margin: 0 0 1rem;
|
|
72
|
+
}
|
|
73
|
+
.device-auth-standalone fieldset {
|
|
74
|
+
border: 0;
|
|
75
|
+
margin: 0 0 1rem;
|
|
76
|
+
min-width: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
}
|
|
79
|
+
.device-auth-standalone legend,
|
|
80
|
+
.device-auth-standalone .label {
|
|
81
|
+
color: #222;
|
|
82
|
+
display: block;
|
|
83
|
+
font-weight: 600;
|
|
84
|
+
margin: 0 0 0.4rem;
|
|
85
|
+
}
|
|
86
|
+
.device-auth-standalone .choice {
|
|
87
|
+
list-style: none;
|
|
88
|
+
margin: 0 0 0.45rem;
|
|
89
|
+
}
|
|
90
|
+
.device-auth-standalone .choice label {
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
gap: 0.45rem;
|
|
93
|
+
align-items: flex-start;
|
|
94
|
+
}
|
|
95
|
+
.device-auth-standalone input[type="text"],
|
|
96
|
+
.device-auth-standalone select {
|
|
97
|
+
border: 1px solid #888;
|
|
98
|
+
border-radius: 2px;
|
|
99
|
+
display: block;
|
|
100
|
+
font: inherit;
|
|
101
|
+
max-width: 100%;
|
|
102
|
+
padding: 0.5rem 0.6rem;
|
|
103
|
+
width: 100%;
|
|
104
|
+
}
|
|
105
|
+
.device-auth-standalone input[type="text"]:focus,
|
|
106
|
+
.device-auth-standalone select:focus,
|
|
107
|
+
.device-auth-standalone input[type="checkbox"]:focus,
|
|
108
|
+
.device-auth-standalone input[type="submit"]:focus {
|
|
109
|
+
outline: 3px solid #1d4f91;
|
|
110
|
+
outline-offset: 2px;
|
|
111
|
+
}
|
|
112
|
+
.device-auth-standalone .device-auth-actions ol {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
gap: 0.65rem;
|
|
116
|
+
list-style: none;
|
|
117
|
+
margin: 0;
|
|
118
|
+
padding: 0;
|
|
119
|
+
}
|
|
120
|
+
.device-auth-standalone .device-auth-actions input[type="submit"],
|
|
121
|
+
.device-auth-standalone fieldset.actions input[type="submit"] {
|
|
122
|
+
background: #1d4f91;
|
|
123
|
+
border: 1px solid #163d70;
|
|
124
|
+
border-radius: 2px;
|
|
125
|
+
color: #fff;
|
|
126
|
+
cursor: pointer;
|
|
127
|
+
font: inherit;
|
|
128
|
+
min-height: 2.5rem;
|
|
129
|
+
padding: 0.45rem 1rem;
|
|
130
|
+
width: 100%;
|
|
131
|
+
}
|
|
132
|
+
.device-auth-standalone .device-auth-actions li:last-child input[type="submit"] {
|
|
133
|
+
background: #fff;
|
|
134
|
+
border-color: #888;
|
|
135
|
+
color: #222;
|
|
136
|
+
}
|
|
137
|
+
@media (min-width: 40rem) {
|
|
138
|
+
.device-auth-standalone .device-auth-actions ol {
|
|
139
|
+
flex-direction: row;
|
|
140
|
+
flex-wrap: wrap;
|
|
141
|
+
}
|
|
142
|
+
.device-auth-standalone .device-auth-actions input[type="submit"],
|
|
143
|
+
.device-auth-standalone fieldset.actions input[type="submit"] {
|
|
144
|
+
width: auto;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="<%= I18n.locale %>">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title><%= t("active_admin.device_authorization.enter_code") %></title>
|
|
7
|
+
<%= render partial: "active_admin/device_authorization/standalone_styles" %>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<main class="device-auth-standalone">
|
|
11
|
+
<h1><%= t("active_admin.device_authorization.enter_code") %></h1>
|
|
12
|
+
<div class="panel">
|
|
13
|
+
<div class="panel-body">
|
|
14
|
+
<%= render partial: "active_admin/device_authorization/enter_code" %>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</main>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="<%= I18n.locale %>">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title><%= t("active_admin.device_authorization.title") %></title>
|
|
7
|
+
<%= render partial: "active_admin/device_authorization/standalone_styles" %>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<main class="device-auth-standalone">
|
|
11
|
+
<%= render partial: "active_admin/device_authorization/consent", locals: {grant: @grant, heading_level: :h1} %>
|
|
12
|
+
</main>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
en:
|
|
2
|
+
active_admin:
|
|
3
|
+
device_authorization:
|
|
4
|
+
menu: Device authorization
|
|
5
|
+
title: Authorize device
|
|
6
|
+
enter_code: Enter the user code
|
|
7
|
+
enter_code_hint: Enter the code shown by the client to review its requested access.
|
|
8
|
+
continue: Continue
|
|
9
|
+
intro: A client asked for a short-lived admin access token. Review the client, scopes, and lifetime before approving.
|
|
10
|
+
verify_code: Verify that this code matches the code shown on the device you are using. Deny the request if the codes do not match.
|
|
11
|
+
client: Client
|
|
12
|
+
user_code: User code
|
|
13
|
+
status: Status
|
|
14
|
+
idle_note: The token also expires after %{idle_hours}h without use, and no later than the absolute lifetime you choose when absolute expiry is enabled.
|
|
15
|
+
scopes: Scopes
|
|
16
|
+
scopes_hint: Uncheck any scope this session should not receive.
|
|
17
|
+
absolute_ttl: Absolute lifetime
|
|
18
|
+
approve: Approve
|
|
19
|
+
deny: Deny
|
|
20
|
+
approved: Request approved. Return to the client; it will receive the token shortly.
|
|
21
|
+
denied: Request denied.
|
|
22
|
+
not_actionable: This request is %{status} and cannot be changed here.
|
|
23
|
+
error:
|
|
24
|
+
not_pending: This request is no longer pending.
|
|
25
|
+
expired: This request expired.
|
|
26
|
+
invalid_scope: Choose at least one valid scope.
|
|
27
|
+
unsupported_scope: One or more scopes are not allowed for this client.
|
|
28
|
+
scope_not_requested: A selected scope was not requested by the client.
|
|
29
|
+
resource_owner_inactive: Your account cannot approve tokens.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
fi:
|
|
2
|
+
active_admin:
|
|
3
|
+
device_authorization:
|
|
4
|
+
menu: Laitteistovaltuutus
|
|
5
|
+
title: Valtuuta laite
|
|
6
|
+
enter_code: Syötä käyttäjäkoodi
|
|
7
|
+
enter_code_hint: Syötä asiakkaan näyttämä koodi ja tarkista sen pyytämät oikeudet.
|
|
8
|
+
continue: Jatka
|
|
9
|
+
intro: Asiakas pyysi lyhytikäistä admin-tunnusta. Tarkista asiakas, oikeudet ja voimassaolo ennen hyväksyntää.
|
|
10
|
+
verify_code: Varmista, että tämä koodi vastaa käyttämäsi laitteen näyttämää koodia. Hylkää pyyntö, jos koodit eivät täsmää.
|
|
11
|
+
client: Asiakas
|
|
12
|
+
user_code: Käyttäjäkoodi
|
|
13
|
+
status: Tila
|
|
14
|
+
idle_note: Tunnus vanhenee myös %{idle_hours} h käyttämättömyyden jälkeen ja viimeistään valitsemasi absoluuttisen ajan kuluttua, jos absoluuttinen vanheneminen on käytössä.
|
|
15
|
+
scopes: Oikeudet
|
|
16
|
+
scopes_hint: Poista valinta oikeuksista, joita tämä istunto ei saa.
|
|
17
|
+
absolute_ttl: Absoluuttinen voimassaolo
|
|
18
|
+
approve: Hyväksy
|
|
19
|
+
deny: Hylkää
|
|
20
|
+
approved: Pyyntö hyväksytty. Palaa asiakkaaseen; se vastaanottaa tunnuksen pian.
|
|
21
|
+
denied: Pyyntö hylätty.
|
|
22
|
+
not_actionable: Tämä pyyntö on tilassa %{status} eikä sitä voi muuttaa täällä.
|
|
23
|
+
error:
|
|
24
|
+
not_pending: Pyyntö ei ole enää odottava.
|
|
25
|
+
expired: Pyyntö vanhentui.
|
|
26
|
+
invalid_scope: Valitse vähintään yksi kelvollinen oikeus.
|
|
27
|
+
unsupported_scope: Yksi tai useampi oikeus ei ole sallittu tälle asiakkaalle.
|
|
28
|
+
scope_not_requested: Valittu oikeus ei ollut asiakkaan pyynnössä.
|
|
29
|
+
resource_owner_inactive: Tilisi ei voi hyväksyä tunnuksia.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
sv:
|
|
2
|
+
active_admin:
|
|
3
|
+
device_authorization:
|
|
4
|
+
menu: Enhetsauktorisering
|
|
5
|
+
title: Auktorisera enhet
|
|
6
|
+
enter_code: Ange användarkoden
|
|
7
|
+
enter_code_hint: Ange koden som klienten visar och granska den begärda åtkomsten.
|
|
8
|
+
continue: Fortsätt
|
|
9
|
+
intro: En klient begärde en kortlivad admin-åtkomsttoken. Kontrollera klient, behörigheter och livstid innan du godkänner.
|
|
10
|
+
verify_code: Kontrollera att den här koden stämmer överens med koden som visas på enheten du använder. Neka begäran om koderna inte stämmer överens.
|
|
11
|
+
client: Klient
|
|
12
|
+
user_code: Användarkod
|
|
13
|
+
status: Status
|
|
14
|
+
idle_note: Token går också ut efter %{idle_hours} h utan användning, och senast efter den absoluta livstid du väljer när absolut utgång är aktiverad.
|
|
15
|
+
scopes: Behörigheter
|
|
16
|
+
scopes_hint: Avmarkera behörigheter som den här sessionen inte ska få.
|
|
17
|
+
absolute_ttl: Absolut livstid
|
|
18
|
+
approve: Godkänn
|
|
19
|
+
deny: Neka
|
|
20
|
+
approved: Begäran godkänd. Gå tillbaka till klienten; den tar emot token snart.
|
|
21
|
+
denied: Begäran nekad.
|
|
22
|
+
not_actionable: Denna begäran är %{status} och kan inte ändras här.
|
|
23
|
+
error:
|
|
24
|
+
not_pending: Begäran väntar inte längre.
|
|
25
|
+
expired: Begäran har gått ut.
|
|
26
|
+
invalid_scope: Välj minst en giltig behörighet.
|
|
27
|
+
unsupported_scope: En eller flera behörigheter tillåts inte för denna klient.
|
|
28
|
+
scope_not_requested: En vald behörighet fanns inte i klientens begäran.
|
|
29
|
+
resource_owner_inactive: Ditt konto kan inte godkänna tokens.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAdmin
|
|
4
|
+
module DeviceAuthorization
|
|
5
|
+
# Pure expiry policy for bearer access tokens.
|
|
6
|
+
# absolute_expires_at and last_used_at are Time-like; config TTLs are seconds or nil.
|
|
7
|
+
class AccessTokenExpiry
|
|
8
|
+
def initialize(config: ActiveAdmin::DeviceAuthorization.config)
|
|
9
|
+
@config = config
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def expired?(absolute_expires_at:, last_used_at:, revoked_at:, now: Time.current)
|
|
13
|
+
return true if revoked_at.present?
|
|
14
|
+
if @config.absolute_expiry_enabled? && absolute_expires_at.present? && absolute_expires_at <= now
|
|
15
|
+
return true
|
|
16
|
+
end
|
|
17
|
+
if @config.idle_expiry_enabled? && last_used_at.present? &&
|
|
18
|
+
last_used_at <= now - @config.access_token_idle_ttl.to_i
|
|
19
|
+
return true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def expires_in_seconds(absolute_expires_at:, last_used_at:, now: Time.current)
|
|
26
|
+
candidates = []
|
|
27
|
+
if @config.absolute_expiry_enabled? && absolute_expires_at.present?
|
|
28
|
+
candidates << (absolute_expires_at - now).to_i
|
|
29
|
+
end
|
|
30
|
+
if @config.idle_expiry_enabled? && last_used_at.present?
|
|
31
|
+
candidates << (last_used_at + @config.access_token_idle_ttl.to_i - now).to_i
|
|
32
|
+
end
|
|
33
|
+
return nil if candidates.empty?
|
|
34
|
+
|
|
35
|
+
[candidates.min, 0].max
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def absolute_expires_at_for(ttl_seconds:, now: Time.current)
|
|
39
|
+
return nil unless @config.absolute_expiry_enabled?
|
|
40
|
+
|
|
41
|
+
clamped = @config.clamp_absolute_ttl(ttl_seconds) || @config.access_token_default_absolute_ttl.to_i
|
|
42
|
+
now + clamped
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAdmin
|
|
4
|
+
module DeviceAuthorization
|
|
5
|
+
module Callback
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def call(callback, **arguments)
|
|
9
|
+
callback&.call(**arguments)
|
|
10
|
+
rescue => error
|
|
11
|
+
Rails.error.report(error, handled: true)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|