@omelhorsite/sdk 0.3.0 → 0.4.1
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.
- package/README.md +113 -131
- package/dist/index.js +1049 -1246
- package/dist/types/auth/device.d.ts +1 -1
- package/dist/types/auth/index.d.ts +2 -2
- package/dist/types/auth/tokens.d.ts +15 -15
- package/dist/types/client.d.ts +10 -10
- package/dist/types/errors.d.ts +12 -15
- package/dist/types/http.d.ts +74 -118
- package/dist/types/index.d.ts +2 -2
- package/dist/types/internal/attachments.d.ts +17 -0
- package/dist/types/internal/helpers.d.ts +9 -0
- package/dist/types/listing.d.ts +90 -0
- package/dist/types/local/qr.d.ts +1 -1
- package/dist/types/local/wordlist.d.ts +2 -3
- package/dist/types/resources/account.d.ts +19 -19
- package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
- package/dist/types/resources/admin/chests.d.ts +51 -0
- package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
- package/dist/types/resources/admin/identities.d.ts +99 -0
- package/dist/types/resources/admin/index.d.ts +77 -0
- package/dist/types/resources/admin/jobs.d.ts +97 -0
- package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
- package/dist/types/resources/admin/notepads.d.ts +49 -0
- package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
- package/dist/types/resources/admin/quotas.d.ts +114 -0
- package/dist/types/resources/admin/shortLinks.d.ts +201 -0
- package/dist/types/resources/admin/types.d.ts +222 -0
- package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
- package/dist/types/resources/admin.d.ts +17 -13
- package/dist/types/resources/auth/index.d.ts +1 -1
- package/dist/types/resources/auth/passkeys.d.ts +127 -163
- package/dist/types/resources/auth/sessions.d.ts +116 -161
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/content/analysis.d.ts +62 -0
- package/dist/types/resources/content/blogs.d.ts +471 -0
- package/dist/types/resources/content/feedbacks.d.ts +263 -0
- package/dist/types/resources/content/index.d.ts +52 -0
- package/dist/types/resources/content/intel/articles.d.ts +230 -0
- package/dist/types/resources/content/intel/config.d.ts +135 -0
- package/dist/types/resources/content/intel/index.d.ts +53 -0
- package/dist/types/resources/content/intel/items.d.ts +91 -0
- package/dist/types/resources/content/intel/reports.d.ts +108 -0
- package/dist/types/resources/content/intel/scripts.d.ts +152 -0
- package/dist/types/resources/content/intel/sources.d.ts +236 -0
- package/dist/types/resources/content/intel/stats.d.ts +105 -0
- package/dist/types/resources/content/intel/types.d.ts +86 -0
- package/dist/types/resources/content/jokes.d.ts +93 -0
- package/dist/types/resources/content/notifications.d.ts +147 -0
- package/dist/types/resources/content/serviceUsages.d.ts +73 -0
- package/dist/types/resources/content/servicesStatus.d.ts +194 -0
- package/dist/types/resources/content/siteConfig.d.ts +43 -0
- package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
- package/dist/types/resources/content.d.ts +41 -236
- package/dist/types/resources/dynamicQrs.d.ts +29 -45
- package/dist/types/resources/forms.d.ts +37 -58
- package/dist/types/resources/jobs.d.ts +35 -44
- package/dist/types/resources/library/annotations.d.ts +162 -0
- package/dist/types/resources/library/books.d.ts +534 -0
- package/dist/types/resources/library/chat.d.ts +259 -0
- package/dist/types/resources/library/index.d.ts +39 -0
- package/dist/types/resources/library/shelves.d.ts +237 -0
- package/dist/types/resources/library/types.d.ts +120 -0
- package/dist/types/resources/library.d.ts +20 -22
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/movies/addons.d.ts +388 -0
- package/dist/types/resources/movies/collections.d.ts +352 -0
- package/dist/types/resources/movies/index.d.ts +29 -0
- package/dist/types/resources/movies/types.d.ts +50 -0
- package/dist/types/resources/movies/watchProgress.d.ts +277 -0
- package/dist/types/resources/movies.d.ts +27 -53
- package/dist/types/resources/music/artists.d.ts +182 -246
- package/dist/types/resources/music/imports.d.ts +190 -218
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +85 -117
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +165 -227
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +38 -47
- package/dist/types/resources/social/groupChats.d.ts +458 -0
- package/dist/types/resources/social/index.d.ts +19 -0
- package/dist/types/resources/social/messages.d.ts +424 -0
- package/dist/types/resources/social/relationships.d.ts +322 -0
- package/dist/types/resources/social/types.d.ts +37 -0
- package/dist/types/resources/social.d.ts +21 -3
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +94 -109
- package/dist/types/resources/tickets.d.ts +19 -10
- package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
- package/dist/types/resources/tools/captions.d.ts +107 -135
- package/dist/types/resources/tools/upscale.d.ts +12 -16
- package/dist/types/types.d.ts +29 -38
- package/package.json +1 -1
|
@@ -8,14 +8,13 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ## What a credential actually is
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* An opaque UUID, and nothing more. `POST /sessions` mints one and hands it
|
|
12
|
+
* back as `token`. That UUID IS the credential.
|
|
13
13
|
*
|
|
14
14
|
* There is no JWT, no signature to verify, no `exp`, no refresh token and no
|
|
15
|
-
* rotation. A session token never expires on its own: it lives until the
|
|
16
|
-
* deleted, which happens on sign-out
|
|
17
|
-
* account
|
|
18
|
-
* deletes it in the database. Do not build refresh logic against this - there
|
|
15
|
+
* rotation. A session token never expires on its own: it lives until the
|
|
16
|
+
* session is deleted, which happens on sign-out or when an administrator
|
|
17
|
+
* deactivates the account. Do not build refresh logic against this - there
|
|
19
18
|
* is nothing to refresh, and a client that "renews" by signing in again just
|
|
20
19
|
* accumulates rows in the user's device list and fires a login alert each time.
|
|
21
20
|
*
|
|
@@ -25,24 +24,22 @@
|
|
|
25
24
|
*
|
|
26
25
|
* ## Three ways the server reads it, and the one that bites
|
|
27
26
|
*
|
|
28
|
-
*
|
|
27
|
+
* The server looks for the token, in this order, in:
|
|
29
28
|
*
|
|
30
29
|
* 1. the `Authorization` header,
|
|
31
30
|
* 2. the `token` request parameter (query string or body),
|
|
32
31
|
* 3. the `oms_session` cookie.
|
|
33
32
|
*
|
|
34
|
-
* and
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* header there really does beat a good `?token=`.)
|
|
33
|
+
* and tries each until one resolves to a LIVE session, so a stale header does
|
|
34
|
+
* not permanently shadow a good cookie on API requests. (The WebSocket
|
|
35
|
+
* handshake is the exception: it takes the FIRST candidate, not the first
|
|
36
|
+
* live one, so a stale header there really does beat a good `?token=`.)
|
|
39
37
|
*
|
|
40
|
-
* The header is
|
|
41
|
-
*
|
|
42
|
-
* spell anything:
|
|
38
|
+
* The header is read by slicing off its FIRST SEVEN CHARACTERS, whatever they
|
|
39
|
+
* are. Nothing checks that those seven characters spell anything:
|
|
43
40
|
*
|
|
44
41
|
* - `Bearer <token>` works (7 chars: `Bearer` plus the space),
|
|
45
|
-
* - `Bearer:<token>` also works,
|
|
42
|
+
* - `Bearer:<token>` also works, since the slice is seven characters either way,
|
|
46
43
|
* - a bare token with NO prefix does NOT work. Its first seven characters are
|
|
47
44
|
* eaten, the remainder matches no row, and the request is answered as
|
|
48
45
|
* anonymous. The failure is a 401 on an endpoint that needs auth, or - far
|
|
@@ -63,17 +60,16 @@
|
|
|
63
60
|
* `SameSite=Lax`, `path=/`, a one-year expiry and NO `Domain` attribute, which
|
|
64
61
|
* makes it host-only: it belongs to `backend.omelhorsite.pt` alone and is never
|
|
65
62
|
* sent to a sibling subdomain. `omelhorsite.pt` and `backend.omelhorsite.pt`
|
|
66
|
-
* share a registrable domain, so a call from
|
|
67
|
-
* same-SITE, and `SameSite=Lax` still lets the cookie ride
|
|
68
|
-
* genuinely different site (
|
|
69
|
-
* a public suffix) can never receive it, no CORS header
|
|
70
|
-
* such a page must use token mode instead.
|
|
63
|
+
* share a registrable domain, so a call from a page on `omelhorsite.pt` is
|
|
64
|
+
* cross-ORIGIN but same-SITE, and `SameSite=Lax` still lets the cookie ride
|
|
65
|
+
* along. A page on a genuinely different site (a `pages.dev` preview, say,
|
|
66
|
+
* where `pages.dev` is a public suffix) can never receive it, no CORS header
|
|
67
|
+
* can change that, and such a page must use token mode instead.
|
|
71
68
|
*
|
|
72
69
|
* ## No CSRF token exists
|
|
73
70
|
*
|
|
74
|
-
* The
|
|
75
|
-
*
|
|
76
|
-
* this SDK that omits one. For browsers the entire cross-site defence is
|
|
71
|
+
* The API issues none. There is no CSRF token to fetch, no header to echo, and
|
|
72
|
+
* nothing in this SDK that omits one. For browsers the entire cross-site defence is
|
|
77
73
|
* `SameSite=Lax` on the cookie; bearer clients are unaffected because a
|
|
78
74
|
* cross-site page cannot make the browser attach an `Authorization` header.
|
|
79
75
|
*
|
|
@@ -88,19 +84,16 @@
|
|
|
88
84
|
* `.update()`, `.follow()`, `.picture()` - the user read and write surface.
|
|
89
85
|
*
|
|
90
86
|
* `DELETE /users/:id` is also absent, and that one is not a delegation: the
|
|
91
|
-
* route cannot succeed for anybody.
|
|
92
|
-
* administrator and then calls `super`, and `CrudActions#destroy` asks
|
|
93
|
-
* `resource.destroyable_by?(Current.user)` - which on `User` is
|
|
94
|
-
* `alias destroyable_by? creatable_by?`, and `creatable_by?` returns `false`
|
|
95
|
-
* unconditionally. Every caller, administrator included, gets
|
|
87
|
+
* route cannot succeed for anybody. Every caller, administrator included, gets
|
|
96
88
|
* `401 "You are not authorized to destroy this resource"`. Use
|
|
97
89
|
* {@link AuthSessionsNamespace.deactivateUser} for the operational need, or
|
|
98
90
|
* {@link AuthSessionsNamespace.deleteAccountStart} for a user deleting
|
|
99
91
|
* themselves, which is a different code path and does work.
|
|
100
92
|
*/
|
|
101
93
|
import { Resource } from "../../http";
|
|
94
|
+
import type { ListParams } from "../../listing";
|
|
102
95
|
import type { AccountSession, User } from "../account";
|
|
103
|
-
import type { Id, Paginated,
|
|
96
|
+
import type { Id, Paginated, RequestOptions } from "../../types";
|
|
104
97
|
/**
|
|
105
98
|
* Name of the httpOnly cookie the backend sets on every session-minting
|
|
106
99
|
* response.
|
|
@@ -113,8 +106,7 @@ import type { Id, Paginated, PageParams, RequestOptions } from "../../types";
|
|
|
113
106
|
export declare const SESSION_COOKIE_NAME = "oms_session";
|
|
114
107
|
/**
|
|
115
108
|
* The seven characters the server slices off the `Authorization` header before
|
|
116
|
-
* looking the token up
|
|
117
|
-
* (`"Bearer:".length`).
|
|
109
|
+
* looking the token up: the length of `"Bearer:"`.
|
|
118
110
|
*
|
|
119
111
|
* Present so the number 7 appears somewhere other than a comment. The transport
|
|
120
112
|
* writes `"Bearer "` (with a space), which is the same length; both forms work
|
|
@@ -122,7 +114,7 @@ export declare const SESSION_COOKIE_NAME = "oms_session";
|
|
|
122
114
|
*/
|
|
123
115
|
export declare const SESSION_BEARER_PREFIX_LENGTH = 7;
|
|
124
116
|
/**
|
|
125
|
-
* Digits in an email verification code
|
|
117
|
+
* Digits in an email verification code.
|
|
126
118
|
*
|
|
127
119
|
* Six, numeric only, zero-padded. This is a deliberate product decision on this
|
|
128
120
|
* project rather than an accident: a code a person can read off a phone and
|
|
@@ -131,19 +123,17 @@ export declare const SESSION_BEARER_PREFIX_LENGTH = 7;
|
|
|
131
123
|
*/
|
|
132
124
|
export declare const VERIFICATION_CODE_LENGTH = 6;
|
|
133
125
|
/**
|
|
134
|
-
* Wrong guesses an issued code survives
|
|
126
|
+
* Wrong guesses an issued code survives.
|
|
135
127
|
*
|
|
136
128
|
* This is the counterweight to a six-digit code, and it is per CODE, not per IP:
|
|
137
|
-
*
|
|
138
|
-
* botnet would otherwise walk a million-key space at 10 guesses a minute per
|
|
129
|
+
* the request throttle only counts by address, so an attacker rotating through
|
|
130
|
+
* a botnet would otherwise walk a million-key space at 10 guesses a minute per
|
|
139
131
|
* address. The budget closes that regardless of where the guesses come from.
|
|
140
132
|
*
|
|
141
133
|
* The exact arithmetic, because off-by-one matters when you are deciding
|
|
142
|
-
* whether to let a user try again:
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* permanent - the row is deleted, not locked - and it also fires a
|
|
146
|
-
* `verification_burned` security alert to the owner. The user's only route
|
|
134
|
+
* whether to let a user try again: four wrong guesses are survivable and the
|
|
135
|
+
* FIFTH burns the code. Burning is permanent - the code is deleted, not locked
|
|
136
|
+
* - and it also sends the owner a security alert. The user's only route
|
|
147
137
|
* forward is a fresh `*_start` call, which is throttled at 4 a minute and 20 an
|
|
148
138
|
* hour per IP, so a client that lets someone mash a code field will lock them
|
|
149
139
|
* out of the flow for the rest of the hour.
|
|
@@ -153,18 +143,15 @@ export declare const VERIFICATION_CODE_LENGTH = 6;
|
|
|
153
143
|
*/
|
|
154
144
|
export declare const VERIFICATION_CODE_MAX_ATTEMPTS = 5;
|
|
155
145
|
/**
|
|
156
|
-
* How long an issued code stays valid
|
|
157
|
-
* milliseconds. Fifteen minutes.
|
|
146
|
+
* How long an issued code stays valid, in milliseconds. Fifteen minutes.
|
|
158
147
|
*
|
|
159
|
-
*
|
|
160
|
-
* issue and every verify, so an expired code behaves exactly like a wrong one:
|
|
148
|
+
* An expired code behaves exactly like a wrong one:
|
|
161
149
|
* `404 "Invalid Verification"`, indistinguishable from the status alone. Show
|
|
162
150
|
* the user a countdown rather than making them find out.
|
|
163
151
|
*/
|
|
164
152
|
export declare const VERIFICATION_CODE_TTL_MS: number;
|
|
165
153
|
/**
|
|
166
|
-
* How long an OAuth handoff ticket stays valid
|
|
167
|
-
* in milliseconds. Two minutes.
|
|
154
|
+
* How long an OAuth handoff ticket stays valid, in milliseconds. Two minutes.
|
|
168
155
|
*
|
|
169
156
|
* The signature window is only half the story - the ticket is also one-time.
|
|
170
157
|
* See {@link AuthSessionsNamespace.adopt}.
|
|
@@ -178,10 +165,10 @@ export declare const OAUTH_TICKET_TTL_MS: number;
|
|
|
178
165
|
* the user can rename it afterwards through `oms.account.sessions.update()`.
|
|
179
166
|
* The list is mostly a joke, with one entry that is not:
|
|
180
167
|
*
|
|
181
|
-
* **`"teapot"` suppresses alerts.**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
168
|
+
* **`"teapot"` suppresses alerts.** A teapot session fires neither the login
|
|
169
|
+
* alert nor the returning-activity alert, which is what an unattended
|
|
170
|
+
* automation wants. Do not relabel a real user's device as a teapot to
|
|
171
|
+
* quieten notifications:
|
|
185
172
|
* you are turning off the only signal that a stolen token is being used.
|
|
186
173
|
*/
|
|
187
174
|
export declare const SESSION_DEVICE_TYPES: readonly ["tablet", "console", "fridge", "teapot", "toaster", "air_conditioner", "car", "blender", "vacuum_cleaner", "washing_machine", "lawn_mower", "microwave", "hair_dryer", "electric_toothbrush", "desktop", "laptop", "television", "mobile", "space_ship", "time_machine", "hoverboard", "teleporter", "magic_carpet", "unicorn", "flying_broom", "submarine", "hot_air_balloon", "keychain", "alarm_clock", "radio", "record_player", "other"];
|
|
@@ -197,18 +184,18 @@ export type SessionDeviceType = (typeof SESSION_DEVICE_TYPES)[number];
|
|
|
197
184
|
* the ten requests a minute the IP is allowed. A user who pastes a code with a
|
|
198
185
|
* trailing space should not lose a fifth of their budget to whitespace.
|
|
199
186
|
*
|
|
200
|
-
* The server
|
|
201
|
-
*
|
|
187
|
+
* The server trims surrounding whitespace, so it is forgiven there; this
|
|
188
|
+
* returns `false` for it anyway, so a caller can trim before
|
|
202
189
|
* sending rather than relying on the remote side to be lenient.
|
|
203
190
|
*/
|
|
204
191
|
export declare function isVerificationCode(value: string): boolean;
|
|
205
192
|
/** Credentials for {@link AuthSessionsNamespace.signIn}. */
|
|
206
193
|
export interface SignInInput {
|
|
207
|
-
/**
|
|
194
|
+
/** Trimmed and lowercased server-side; send it as the user typed it. */
|
|
208
195
|
readonly email: string;
|
|
209
196
|
/**
|
|
210
|
-
* Compared
|
|
211
|
-
*
|
|
197
|
+
* Compared in constant time: a wrong password and an unknown address take
|
|
198
|
+
* the same time and give the same
|
|
212
199
|
* message, so this endpoint cannot be used to test whether an account exists.
|
|
213
200
|
*/
|
|
214
201
|
readonly password: string;
|
|
@@ -216,15 +203,13 @@ export interface SignInInput {
|
|
|
216
203
|
/**
|
|
217
204
|
* What `POST /sessions` answers with: the session record plus, ONCE, the token.
|
|
218
205
|
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* `user`. That inline user saves a round trip: there is no need to call
|
|
223
|
-
* `oms.account.me()` straight after signing in.
|
|
206
|
+
* Everything an ordinary {@link AccountSession} carries is here too, including
|
|
207
|
+
* the inlined `user`, plus `token`. That inline user saves a round trip: there
|
|
208
|
+
* is no need to call `oms.account.me()` straight after signing in.
|
|
224
209
|
*
|
|
225
210
|
* `token` appears in this response and in NO other. Nothing else in the API
|
|
226
|
-
* ever renders it again: `GET /sessions` and `GET /sessions/mine`
|
|
227
|
-
*
|
|
211
|
+
* ever renders it again: `GET /sessions` and `GET /sessions/mine` never
|
|
212
|
+
* include a `token` field. Lose it and the only way back is to
|
|
228
213
|
* sign in again, minting another row.
|
|
229
214
|
*/
|
|
230
215
|
export interface SignedInSession extends AccountSession {
|
|
@@ -232,7 +217,7 @@ export interface SignedInSession extends AccountSession {
|
|
|
232
217
|
* The credential. A bare UUID, no prefix.
|
|
233
218
|
*
|
|
234
219
|
* Store it where the platform stores secrets (Keychain / Keystore via
|
|
235
|
-
* SecureStore on React Native, the OS keyring
|
|
220
|
+
* SecureStore on React Native, the OS keyring on a desktop). Do NOT store it
|
|
236
221
|
* when you are in cookie mode - see {@link AuthSessionsNamespace.signIn}.
|
|
237
222
|
*/
|
|
238
223
|
readonly token: string;
|
|
@@ -266,7 +251,7 @@ export interface SignUpInput {
|
|
|
266
251
|
readonly code: string;
|
|
267
252
|
/**
|
|
268
253
|
* Display name, 1 to 50 characters. The `handle` is NOT settable here: the
|
|
269
|
-
* server generates one from this name
|
|
254
|
+
* server generates one from this name. Change it
|
|
270
255
|
* afterwards with `oms.account.update({ handle })`.
|
|
271
256
|
*/
|
|
272
257
|
readonly name: string;
|
|
@@ -291,14 +276,10 @@ export interface ChangeEmailInput {
|
|
|
291
276
|
/** The six digits sent to the new address. */
|
|
292
277
|
readonly newEmailCode: string;
|
|
293
278
|
}
|
|
294
|
-
/**
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
* :handle` on the controller). Any other key is rejected with `400 "Unknown
|
|
299
|
-
* search filter"`, not ignored - this list DSL fails closed.
|
|
300
|
-
*/
|
|
301
|
-
export interface ListUsersParams extends PageParams {
|
|
279
|
+
/** Filter columns of `GET /users`, on top of {@link BASE_FILTER_COLUMNS}. */
|
|
280
|
+
export declare const USER_FILTER_COLUMNS: readonly ["name", "handle"];
|
|
281
|
+
/** Filters for {@link AuthSessionsNamespace.listUsers}. */
|
|
282
|
+
export interface ListUsersParams extends ListParams<(typeof USER_FILTER_COLUMNS)[number]> {
|
|
302
283
|
/** Substring match on the display name, accent-folded and case-insensitive. */
|
|
303
284
|
readonly name?: string;
|
|
304
285
|
/** Substring match on the handle, accent-folded and case-insensitive. */
|
|
@@ -325,7 +306,7 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
325
306
|
*
|
|
326
307
|
* ## What to do with the answer, per mode
|
|
327
308
|
*
|
|
328
|
-
* **Token mode** (React Native,
|
|
309
|
+
* **Token mode** (React Native, Bun, anything not served from
|
|
329
310
|
* `omelhorsite.pt`): store `token` in the platform's secret store and build a
|
|
330
311
|
* client with it. The client you called this on has no credential, and adding
|
|
331
312
|
* one to an existing client is not possible - `Oms` takes its token at
|
|
@@ -357,9 +338,6 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
357
338
|
* re-creates precisely the XSS-exfiltratable copy the cookie mode exists to
|
|
358
339
|
* eliminate, and it also gives you a second credential that outlives the
|
|
359
340
|
* first: sign out, and the cookie dies while the stored token keeps working.
|
|
360
|
-
* The web app is explicit about this - `persistSessionToken` writes only a
|
|
361
|
-
* non-sensitive `authed` flag when `isCookieAuth()`, and actively purges any
|
|
362
|
-
* legacy token it finds.
|
|
363
341
|
*
|
|
364
342
|
* Note that an `Oms` cannot be both: passing `sessionCookie: true` together
|
|
365
343
|
* with a token throws a `TypeError` at construction, deliberately, so that no
|
|
@@ -367,14 +345,13 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
367
345
|
*
|
|
368
346
|
* ## Cost and failure
|
|
369
347
|
*
|
|
370
|
-
* Throttled to **10 POSTs per minute per IP
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
* gap was closed.
|
|
348
|
+
* Throttled to **10 POSTs per minute per IP**, which is a password-guessing
|
|
349
|
+
* bound and is keyed by address, so several users behind one NAT share it.
|
|
350
|
+
* The throttle matches a normalised path, so `/sessions/`, `//sessions` and
|
|
351
|
+
* `/sessions.json` all count against the same bucket.
|
|
375
352
|
*
|
|
376
|
-
* Every successful sign-in creates a
|
|
377
|
-
*
|
|
353
|
+
* Every successful sign-in creates a session AND sends the owner a login
|
|
354
|
+
* alert. Signing in once per process invocation is how a device list fills up
|
|
378
355
|
* with a hundred identical entries; persist the token instead.
|
|
379
356
|
*
|
|
380
357
|
* Retries: an ambiguous network failure is NOT replayed, because this is a
|
|
@@ -392,8 +369,7 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
392
369
|
*
|
|
393
370
|
* @throws {OmsAuthError} 401 `"Invalid email address or password."` for a
|
|
394
371
|
* wrong password, an unknown address, and a deactivated account alike. The
|
|
395
|
-
* three are not distinguishable, on purpose.
|
|
396
|
-
* validation on `Session` create, so it fails at the same place.)
|
|
372
|
+
* three are not distinguishable, on purpose.
|
|
397
373
|
* @throws {OmsQuotaError} 429 once the per-IP login budget is spent.
|
|
398
374
|
*/
|
|
399
375
|
signIn(input: SignInInput, options?: RequestOptions): Promise<SignedInSession>;
|
|
@@ -402,12 +378,10 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
402
378
|
*
|
|
403
379
|
* ## THE `:id` IS IGNORED. THIS ALWAYS DESTROYS THE CALLING SESSION.
|
|
404
380
|
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
* device. The web app's own "sign out this other device" button has always
|
|
410
|
-
* signed the user out of the browser they clicked it in.
|
|
381
|
+
* The server never looks the path segment up. It destroys the calling
|
|
382
|
+
* session, clears the cookie and answers `204`. So
|
|
383
|
+
* `DELETE /sessions/<any string at all>` means "log ME out", and there is no
|
|
384
|
+
* way through this API to revoke a different device.
|
|
411
385
|
*
|
|
412
386
|
* That is why this method takes no id. A signature that accepted one would be
|
|
413
387
|
* describing behaviour the server does not have, and the mistake it invites -
|
|
@@ -415,7 +389,7 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
415
389
|
* with a `204` that looks like success.
|
|
416
390
|
*
|
|
417
391
|
* To actually end someone else's sessions there is exactly one lever, and it
|
|
418
|
-
* is administrative: {@link deactivateUser}
|
|
392
|
+
* is administrative: {@link deactivateUser} ends every session of the
|
|
419
393
|
* target.
|
|
420
394
|
*
|
|
421
395
|
* ## What it does on the wire
|
|
@@ -447,20 +421,19 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
447
421
|
/**
|
|
448
422
|
* `GET /sessions/mine` - the session the current credential resolves to.
|
|
449
423
|
*
|
|
450
|
-
* The cheapest liveness check there is, and the one
|
|
451
|
-
*
|
|
452
|
-
*
|
|
424
|
+
* The cheapest liveness check there is, and the one an app should boot with:
|
|
425
|
+
* a `200` means the stored credential still names a live session, a `401`
|
|
426
|
+
* means it does not and the user must sign in again. Identical
|
|
453
427
|
* to `oms.account.sessions.current()`; both are here because "am I still
|
|
454
428
|
* signed in" belongs to the sign-in lifecycle and "which devices are signed
|
|
455
429
|
* in" belongs to the account screen.
|
|
456
430
|
*
|
|
457
|
-
* Returns the
|
|
458
|
-
* `
|
|
431
|
+
* Returns the session with the owner inlined under `user` and WITHOUT
|
|
432
|
+
* `token`. There is no route that hands a token back.
|
|
459
433
|
*
|
|
460
434
|
* `/sessions/mine` is the whole spelling. There is NO `GET /sessions/current`:
|
|
461
|
-
* `
|
|
462
|
-
*
|
|
463
|
-
* 404. (It IS a live path on DELETE, where it is the placeholder id
|
|
435
|
+
* `GET /sessions/:id` is not routed at all, so a GET to `/sessions/current`
|
|
436
|
+
* is a 404. (It IS a live path on DELETE, where it is the placeholder id
|
|
464
437
|
* {@link signOut} uses, which is exactly the sort of coincidence that makes
|
|
465
438
|
* the wrong spelling look plausible.)
|
|
466
439
|
*
|
|
@@ -484,8 +457,8 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
484
457
|
*
|
|
485
458
|
* The last step of the browser OAuth flow. The provider round trip happens on
|
|
486
459
|
* the API host; its callback redirects the browser back to
|
|
487
|
-
* `https://omelhorsite.pt/account/oauth/callback?ticket=...` (
|
|
488
|
-
*
|
|
460
|
+
* `https://omelhorsite.pt/account/oauth/callback?ticket=...` (fixed
|
|
461
|
+
* server-side, not configurable per client), and the
|
|
489
462
|
* page hands that ticket here. The ticket exists so the session token itself
|
|
490
463
|
* never travels in a URL, a browser history entry or a `Referer`.
|
|
491
464
|
*
|
|
@@ -496,10 +469,9 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
496
469
|
*
|
|
497
470
|
* ## MUST NOT BE RETRIED, and this method enforces that
|
|
498
471
|
*
|
|
499
|
-
* The ticket is one-time on the server. Redemption is claimed atomically
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
* expired ticket."` as a forged one. So a retry after an ambiguous failure -
|
|
472
|
+
* The ticket is one-time on the server. Redemption is claimed atomically
|
|
473
|
+
* before the session is adopted, and a second presentation of the same
|
|
474
|
+
* ticket gets the same `401 "Invalid or expired ticket."` as a forged one. So a retry after an ambiguous failure -
|
|
503
475
|
* a torn connection, a lost response - burns the ticket and reports a login
|
|
504
476
|
* failure for a login that actually SUCCEEDED. The user is left staring at an
|
|
505
477
|
* error page while the browser quietly holds a valid session cookie.
|
|
@@ -508,12 +480,6 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
508
480
|
* back on. If the call fails ambiguously, the honest recovery is to check
|
|
509
481
|
* {@link current} before deciding anything: if it answers, you are signed in.
|
|
510
482
|
*
|
|
511
|
-
* The app-side documentation (`oms-music/docs/auth-account.md`, section 6)
|
|
512
|
-
* says the ticket is "not single-use server-side" and that the web enforces
|
|
513
|
-
* single use client-side with a sessionStorage nonce. THAT IS OUT OF DATE.
|
|
514
|
-
* The Rails code enforces it, and it is the enforcement that makes a retry
|
|
515
|
-
* destructive. When the doc and the Rails disagree, the Rails wins.
|
|
516
|
-
*
|
|
517
483
|
* Tickets are also short-lived, {@link OAUTH_TICKET_TTL_MS} (two minutes), so
|
|
518
484
|
* do not stash one to redeem later.
|
|
519
485
|
*
|
|
@@ -525,7 +491,7 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
525
491
|
* `GET /sessions/oauth_ticket` - mints a short-lived ticket for the current
|
|
526
492
|
* session, so the session token itself never crosses a subdomain boundary.
|
|
527
493
|
*
|
|
528
|
-
* Only
|
|
494
|
+
* Only a browser page needs this, and only for one thing: linking an OAuth
|
|
529
495
|
* provider to an account that is already signed in. That flow is a full-page
|
|
530
496
|
* navigation to `backend.omelhorsite.pt/auth/link/<provider>`, and a
|
|
531
497
|
* navigation cannot carry an `Authorization` header. The cookie is host-only
|
|
@@ -533,8 +499,8 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
533
499
|
* `?token=<the session token>` in a URL that lands in browser history and in
|
|
534
500
|
* a `Referer`, which is exactly what this endpoint exists to avoid.
|
|
535
501
|
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
502
|
+
* A token-mode client has no such constraint and does not need this: it
|
|
503
|
+
* holds the token already.
|
|
538
504
|
*
|
|
539
505
|
* The result is scoped to the `oauth` purpose and expires after
|
|
540
506
|
* {@link OAUTH_TICKET_TTL_MS}. It authenticates nothing else - an API call
|
|
@@ -565,9 +531,9 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
565
531
|
* is a deliberate trade for a usable signup form, and it is why
|
|
566
532
|
* {@link resetPasswordStart} does the opposite.
|
|
567
533
|
*
|
|
568
|
-
* Issuing a code DELETES any live code for the same address and
|
|
569
|
-
*
|
|
570
|
-
*
|
|
534
|
+
* Issuing a code DELETES any live code for the same address and flow. One
|
|
535
|
+
* code per flow per address, always. A user who asks for a second code and
|
|
536
|
+
* then types the first
|
|
571
537
|
* one gets `404 "Invalid Verification"` and, worse, spends one of the five
|
|
572
538
|
* guesses belonging to the code they cannot see. Tell them the old code is
|
|
573
539
|
* dead when they request a new one.
|
|
@@ -592,9 +558,8 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
592
558
|
*
|
|
593
559
|
* No session is created and no token is returned. The account exists and the
|
|
594
560
|
* caller is still anonymous. Follow it immediately with {@link signIn} using
|
|
595
|
-
* the same email and password
|
|
596
|
-
*
|
|
597
|
-
* still on the login screen" bug.
|
|
561
|
+
* the same email and password; forgetting it is the classic "signup worked
|
|
562
|
+
* but the app is still on the login screen" bug.
|
|
598
563
|
*
|
|
599
564
|
* ```ts
|
|
600
565
|
* await oms.sessions.signUpStart(email);
|
|
@@ -603,12 +568,11 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
603
568
|
* const session = await oms.sessions.signIn({ email, password });
|
|
604
569
|
* ```
|
|
605
570
|
*
|
|
606
|
-
* `handle` cannot be chosen here
|
|
607
|
-
*
|
|
608
|
-
* from `name`. Let the user change it afterwards with
|
|
571
|
+
* `handle` cannot be chosen here: the parameter is ignored, and the server
|
|
572
|
+
* generates one from `name`. Let the user change it afterwards with
|
|
609
573
|
* `oms.account.update({ handle })`, where 15 characters is the ceiling.
|
|
610
574
|
*
|
|
611
|
-
* Consuming the code also
|
|
575
|
+
* Consuming the code also marks the address as verified.
|
|
612
576
|
* The address is proven, so a freshly signed-up account is never in the
|
|
613
577
|
* "verify your email" limbo.
|
|
614
578
|
*
|
|
@@ -637,8 +601,7 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
637
601
|
* present this result to the user as confirmation that mail is on its way to
|
|
638
602
|
* a real account, because it is not evidence of that.
|
|
639
603
|
*
|
|
640
|
-
* A real send also
|
|
641
|
-
* owner.
|
|
604
|
+
* A real send also sends the owner a security alert.
|
|
642
605
|
*
|
|
643
606
|
* Same throttle family as every other `*_start`: **4 a minute and 20 an hour
|
|
644
607
|
* per IP**, shared.
|
|
@@ -659,7 +622,7 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
659
622
|
* other sessions ({@link signOut} only ends the caller's). Escalating to an
|
|
660
623
|
* administrator and {@link deactivateUser} is the only lever that clears them.
|
|
661
624
|
*
|
|
662
|
-
* Consuming the code
|
|
625
|
+
* Consuming the code marks the address as verified: proving control of the
|
|
663
626
|
* mailbox verifies the address even if it never was verified before.
|
|
664
627
|
*
|
|
665
628
|
* Throttled to **10 a minute per IP**, shared with the other `*_end`
|
|
@@ -678,9 +641,8 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
678
641
|
* `POST /users/update_email_start` - emails TWO codes: one to the address
|
|
679
642
|
* currently on the account, one to the address it is moving to.
|
|
680
643
|
*
|
|
681
|
-
* Requires a live session. One HTTP request, two
|
|
682
|
-
*
|
|
683
|
-
* {@link changeEmailComplete} needs both codes back. Proving control of the
|
|
644
|
+
* Requires a live session. One HTTP request, two codes, and
|
|
645
|
+
* {@link changeEmailComplete} needs both back. Proving control of the
|
|
684
646
|
* new mailbox alone is not enough: an attacker sitting on a hijacked session
|
|
685
647
|
* would otherwise move the account to an address they own and lock the real
|
|
686
648
|
* owner out permanently.
|
|
@@ -709,17 +671,16 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
709
671
|
*
|
|
710
672
|
* Requires a live session; answers `200` with the updated {@link User}.
|
|
711
673
|
*
|
|
712
|
-
* Both codes are checked BEFORE either is consumed
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
* two codes into the wrong boxes spends one of the five guesses on each. With
|
|
674
|
+
* Both codes are checked BEFORE either is consumed, so getting one right and
|
|
675
|
+
* one wrong burns neither. What it does still cost is an attempt against
|
|
676
|
+
* BOTH live codes: a wrong guess counts against the code it was meant for,
|
|
677
|
+
* so a user typing the two codes into the wrong boxes spends one of the five
|
|
678
|
+
* guesses on each. With
|
|
718
679
|
* two codes in play the per-code budget is easier to exhaust than anywhere
|
|
719
680
|
* else in this family - validate with {@link isVerificationCode} first, and
|
|
720
681
|
* label the two inputs unmistakably.
|
|
721
682
|
*
|
|
722
|
-
* Consuming both
|
|
683
|
+
* Consuming both marks the address as verified, since both mailboxes are proven.
|
|
723
684
|
*
|
|
724
685
|
* Throttled to **10 a minute per IP**, shared with the other `*_end`
|
|
725
686
|
* endpoints.
|
|
@@ -748,19 +709,15 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
748
709
|
* Answers `200` with the bare string `"User deletion instructions sent."`.
|
|
749
710
|
* Shared `*_start` throttle: **4 a minute and 20 an hour per IP**.
|
|
750
711
|
*
|
|
751
|
-
* Included here even though it is the one pair of routes the sibling
|
|
752
|
-
* documentation does not list, because nothing else in the SDK covers it and
|
|
753
|
-
* a user who cannot delete their account has no exit.
|
|
754
|
-
*
|
|
755
712
|
* @throws {OmsAuthError} 401 without a live session.
|
|
756
713
|
*/
|
|
757
714
|
deleteAccountStart(options?: RequestOptions): Promise<string>;
|
|
758
715
|
/**
|
|
759
716
|
* `POST /users/destroy_end` - presents the code and DESTROYS THE ACCOUNT.
|
|
760
717
|
*
|
|
761
|
-
* Requires a live session. Irreversible:
|
|
762
|
-
*
|
|
763
|
-
*
|
|
718
|
+
* Requires a live session. Irreversible: it takes the user's sessions,
|
|
719
|
+
* files, music library and everything else with it. There is no soft-delete
|
|
720
|
+
* on this path and no undo.
|
|
764
721
|
* {@link deactivateUser} is the reversible operation, and it is
|
|
765
722
|
* administrators only.
|
|
766
723
|
*
|
|
@@ -774,32 +731,30 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
774
731
|
* @throws {OmsAuthError} 401 without a live session.
|
|
775
732
|
* @throws {OmsApiError} 404 `"Invalid Verification"` for a wrong, expired or
|
|
776
733
|
* burned code.
|
|
777
|
-
* @throws {OmsApiError} 500 with the
|
|
778
|
-
* could not be destroyed
|
|
779
|
-
* account survives; the code does not.
|
|
734
|
+
* @throws {OmsApiError} 500 with the server's error messages when the
|
|
735
|
+
* account could not be destroyed. The account survives; the code does not.
|
|
780
736
|
*/
|
|
781
737
|
deleteAccountComplete(code: string, options?: RequestOptions): Promise<void>;
|
|
782
738
|
/**
|
|
783
739
|
* `GET /users` - the user roster.
|
|
784
740
|
*
|
|
785
741
|
* Requires a credential, and any authenticated account can enumerate the
|
|
786
|
-
* whole
|
|
787
|
-
*
|
|
742
|
+
* whole roster. What an ordinary caller does NOT get is the privileged
|
|
743
|
+
* columns - `group`, `email`, `gender`,
|
|
788
744
|
* `last_seen_at`, `sessions_count`, `deactivated_at` and
|
|
789
745
|
* `allowed_to_use_spotify` are all rendered conditionally, so an absent key
|
|
790
746
|
* means "not visible to you", never "empty".
|
|
791
747
|
*
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
* anonymous, capped at eight rows, and returns only id, handle and name.
|
|
748
|
+
* For a picker, prefer `oms.account.search()`: it is anonymous, capped at
|
|
749
|
+
* eight rows, and returns only id, handle and name.
|
|
795
750
|
*
|
|
796
751
|
* Only `name` and `handle` are filterable. Any other key is a `400 "Unknown
|
|
797
752
|
* search filter"` - this DSL fails closed rather than ignoring what it does
|
|
798
753
|
* not recognise.
|
|
799
754
|
*
|
|
800
|
-
* Deactivated accounts are NOT filtered out of this listing (
|
|
801
|
-
*
|
|
802
|
-
*
|
|
755
|
+
* Deactivated accounts are NOT filtered out of this listing (unlike
|
|
756
|
+
* `oms.account.search()`), so a roster shows them; an administrator can tell
|
|
757
|
+
* by `deactivated_at`, and nobody else can.
|
|
803
758
|
*
|
|
804
759
|
* Index responses carry an `ETag`, so a repeat can answer `304` with no body.
|
|
805
760
|
* Counts against the general authenticated ceiling, 600 a minute.
|
|
@@ -810,10 +765,10 @@ export declare class AuthSessionsNamespace extends Resource {
|
|
|
810
765
|
*
|
|
811
766
|
* ## This is also the only way to revoke somebody's sessions
|
|
812
767
|
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
*
|
|
768
|
+
* Deactivation stamps `deactivated_at` and ends every session of the target
|
|
769
|
+
* at once, so every device they are signed in on is logged out, and a new
|
|
770
|
+
* sign-in is refused. It is the single lever in this API that ends a session
|
|
771
|
+
* other
|
|
817
772
|
* than the caller's own - {@link signOut} cannot, and neither can anything in
|
|
818
773
|
* `oms.account.sessions`. If a token has leaked, this is the response.
|
|
819
774
|
*
|