@crossauth/common 0.0.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.
@@ -0,0 +1,262 @@
1
+ /**
2
+ * A key (eg session ID, email reset token) as stored in a database table.
3
+ *
4
+ * The fields defined here are the ones used by Crossauth. You may add
5
+ * others.
6
+ */
7
+ export interface Key {
8
+ /** The value of the keykey.
9
+ *
10
+ * In a cookie, the value part of cookiename=value; options...
11
+ */
12
+ value: string;
13
+ /** The date/time the key was created, in local time on the server */
14
+ created: Date;
15
+ /** The date/time the key expires */
16
+ expires: Date | undefined;
17
+ /** the user this key is for (or undefined for an anonymous session ID)
18
+ *
19
+ * It accepts the value null as usually this is the value stored in the
20
+ * database, rather than undefined. Some functions need to differentiate
21
+ * between a null value as opposed to the value not being defined (eg for
22
+ * a partial update).
23
+ */
24
+ userid: string | number | undefined | null;
25
+ /** The date/time key was last used (eg last time a request was made
26
+ * with this value as a session ID)
27
+ */
28
+ lastactive?: Date;
29
+ /** Additional key-specific data (eg new email address for email change).
30
+ *
31
+ * While application specific, any data Crossauth puts in this field
32
+ * is a stringified JSON, with its own key so it can co-exist with
33
+ * other data.
34
+ */
35
+ data?: string;
36
+ /** This allows users to add additional fields, which if present in the
37
+ * database will be loaded into this object.
38
+ */
39
+ [key: string]: any;
40
+ }
41
+ /**
42
+ * An API key is a string that can be used in place of a username and
43
+ * password. These are not automatically created, like OAuth access tokens.
44
+ */
45
+ export interface ApiKey extends Key {
46
+ /** A name for the key, unique to the user */
47
+ name: string;
48
+ }
49
+ /**
50
+ * Given a key object, parses JSON data in the `data` field anmd returns
51
+ * it as an object
52
+ * @param key the key object containing the data to parse in `data`.
53
+ * @returns an object with the parsed JSON data.
54
+ */
55
+ export declare function getJsonData(key: Key): {
56
+ [key: string]: any;
57
+ };
58
+ /**
59
+ * Describes a user as fetched from the user storage (eg, database table),
60
+ * excluding auto-generated fields such as an auto-generated ID
61
+ *
62
+ * This is extendible with additional fields - provide them to the
63
+ * {@link @crossauth/backend!UserStorage} class as `extraFields`.
64
+ *
65
+ * You may want to do this if you want to pass additional user data back to the
66
+ * caller, eg real name.
67
+ *
68
+ * The fields defined here are the ones used by Crossauth. You may add
69
+ * others.
70
+ */
71
+ export interface UserInputFields {
72
+ /** The username. This may be an email address or anything else,
73
+ * application-specific.
74
+ */
75
+ username: string;
76
+ /**
77
+ * You are free to define your own states. The ones Crossauth recognises
78
+ * are defined in {@link UserState}.
79
+ */
80
+ state: string;
81
+ /**
82
+ * You can optionally include an email address field in your user table.
83
+ * If your username is an email address, you do not need a separate field.
84
+ */
85
+ email?: string;
86
+ /**
87
+ * Whether or not the user has administrator priviledges (and can acess
88
+ * admin-only functions).
89
+ */
90
+ admin?: boolean;
91
+ /**
92
+ * This is included as any other fields in your user table will
93
+ * automatically be added to the user object if they are included in
94
+ * `extraFields` in {@link @crossauth/backend!UserStorage}.
95
+ */
96
+ [key: string]: any;
97
+ }
98
+ /**
99
+ * This adds ID to {@link UserInputFields}.
100
+ *
101
+ * If your `username` field is
102
+ * unique and immutable, you can omit ID (passing username anywhere an ID)
103
+ * is expected. However, if you want users to be able to change their username,
104
+ * you should include ID field and make that immutable instead.
105
+ */
106
+ export interface User extends UserInputFields {
107
+ /** ID fied, which may be auto-generated */
108
+ id: string | number;
109
+ }
110
+ /**
111
+ * Secrets, such as a password, are not in the User object to prevent them
112
+ * accidentally being leaked to the frontend. All functions that return
113
+ * secrets return them in this separate object.
114
+ *
115
+ * The fields in this class are the ones that are not autogenerated by the
116
+ * database.
117
+ */
118
+ export interface UserSecretsInputFields {
119
+ password?: string;
120
+ totpsecret?: string;
121
+ otp?: string;
122
+ expiry?: number;
123
+ [key: string]: any;
124
+ }
125
+ /**
126
+ * This adds the user ID toi {@link UserSecretsInputFields}.
127
+ */
128
+ export interface UserSecrets extends UserSecretsInputFields {
129
+ userid: string | number;
130
+ }
131
+ /** OAuth client data as stored in a database table */
132
+ export interface OAuthClient {
133
+ /** The client_id, which is auto-generated and immutable */
134
+ client_id: string;
135
+ /** Whether or not the client is confidential (and can therefore
136
+ * keep the client secret secret) */
137
+ confidential: boolean;
138
+ /**
139
+ * A user-friendly name for the client (not used as part of the OAuth
140
+ * API).
141
+ */
142
+ client_name: string;
143
+ /**
144
+ * Client secret, which is autogenerated.
145
+ *
146
+ * If there is no client secret, it should be set to `undefined`.
147
+ *
148
+ * This field allows `null` as well as `undefined` this is used, for
149
+ * example, when partially updating a client and you specifically
150
+ * want to set the secret to undefined, as opposed to just not wishing
151
+ * to change the value. Other than that, this value is always either
152
+ * a string or `undefined`.
153
+ */
154
+ client_secret?: string | null;
155
+ /**
156
+ * An array of value redirect URIs for the client.
157
+ */
158
+ redirect_uri: string[];
159
+ /**
160
+ * An array of OAuth flows allowed for this client.
161
+ *
162
+ * See {@link @crossauth/common!OAuthFlows}.
163
+ */
164
+ valid_flow: string[];
165
+ /**
166
+ * ID of the user who owns this client, which may be `undefined`
167
+ * for not being owned by a specific user.
168
+ *
169
+ * This field allows `null` as well as `undefined` this is used, for
170
+ * example, when partially updating a client and you specifically
171
+ * want to set the user ID to undefined, as opposed to just not wishing
172
+ * to change the value. Other than that, this value is always either
173
+ * a string or number (depending on the ID type in your user storage)
174
+ * or `undefined`.
175
+ */
176
+ userid?: string | number | null;
177
+ [key: string]: any;
178
+ }
179
+ /**
180
+ * Although the `state` field in {@link User} can be any string, these
181
+ * are the values recognised and used by Crossauth.
182
+ */
183
+ export declare class UserState {
184
+ /** Ordinary, active user who can log in freely */
185
+ static readonly active = "active";
186
+ /** Deactivated account. User cannot log in */
187
+ static readonly disabled = "disabled";
188
+ /** Two factor authentication has been actived for this user
189
+ * but has not yet been configured. Once a user logs in,
190
+ * they will be directed to a page to configure 2FA and will
191
+ * not be able to do anything else (that requires login) until
192
+ * they have done so.
193
+ */
194
+ static readonly awaitingTwoFactorSetup = "awaitingtwofactorsetup";
195
+ /** Email verification has been turned on but user has not
196
+ * verified his or her email address. Cannot log on until it has
197
+ * been verified.
198
+ */
199
+ static readonly awaitingEmailVerification = "awaitingemailverification";
200
+ /**
201
+ * If the state is set to this, the user may not access any
202
+ * login-required functions unless he or she has changed their password.
203
+ *
204
+ * Upon login, the user is redirected to the change password page.
205
+ */
206
+ static readonly passwordChangeNeeded = "passwordchangeneeded";
207
+ /**
208
+ * If the state is set to this, the user may not access any
209
+ * login-required functions unless he or she has reset their password.
210
+ *
211
+ * Upon login, the user is redirected to the reset password page.
212
+ */
213
+ static readonly passwordResetNeeded = "passwordresetneeded";
214
+ /**
215
+ * If the state is set to this, the user may not access any
216
+ * login-required functions unless he or she has reset their second
217
+ * factor configuration.
218
+ *
219
+ * Upon login, the user is redirected to the 2FA configuration page.
220
+ *
221
+ * If you create a user and 2FA is mandatory, you can set state to
222
+ * this value and the user will then be prompted to configure 2FA
223
+ * upon login.
224
+ */
225
+ static readonly factor2ResetNeeded = "factor2resetneeded";
226
+ /**
227
+ * If the state is set to this, the user may not access any
228
+ * login-required functions unless he or she has reset their password
229
+ * and then resets factor2.
230
+ *
231
+ * Upon login, the user is redirected to the reset password page.
232
+ */
233
+ static readonly passwordAndFactor2ResetNeeded = "passwordandfactor2resetneeded";
234
+ }
235
+ /**
236
+ * You can have one key table for everything or separate key tables for
237
+ * different types of keys. So that different types of keys can
238
+ * coexist, their values are prefixed by these strings
239
+ */
240
+ export declare class KeyPrefix {
241
+ /** Session ID */
242
+ static readonly session = "s:";
243
+ /** Password Reset Token */
244
+ static readonly passwordResetToken = "p:";
245
+ /** Email verification token */
246
+ static readonly emailVerificationToken = "e:";
247
+ /** API key */
248
+ static readonly apiKey = "api:";
249
+ /** OAuth authorization code */
250
+ static readonly authorizationCode = "authz:";
251
+ /** OAuth access token */
252
+ static readonly accessToken = "access:";
253
+ /** OAuth refresh token */
254
+ static readonly refreshToken = "refresh:";
255
+ /** OAuth MFA key (used by the password MFA flow) */
256
+ static readonly mfaToken = "omfa:";
257
+ /** Device code device code */
258
+ static readonly deviceCode = "dc:";
259
+ /** Device code flow user code */
260
+ static readonly userCode = "uc:";
261
+ }
262
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"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"}
package/dist/jwt.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Encapsulates the payload of a JWT, with both the token and
3
+ * decoded JSON payload.
4
+ */
5
+ export declare class JWT {
6
+ /** The string representation of the JWT */
7
+ token: string | undefined;
8
+ /** The decoded payload from the token */
9
+ payload: {
10
+ [key: string]: any;
11
+ };
12
+ /**
13
+ * Constructor. Pass either `token` or `payload`.
14
+ * @param token the string JWT token - the payload will be parsed from it
15
+ * @param payload the JSON payload. The payload will be set but not
16
+ * the string `token`.
17
+ */
18
+ constructor({ token, payload }: {
19
+ token?: string;
20
+ payload?: {
21
+ [key: string]: any;
22
+ };
23
+ });
24
+ }
25
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,qBAAa,GAAG;IAEZ,2CAA2C;IAC3C,KAAK,EAAG,MAAM,GAAC,SAAS,CAAC;IAEzB,yCAAyC;IACzC,OAAO,EAAG;QAAC,CAAC,GAAG,EAAC,MAAM,GAAG,GAAG,CAAA;KAAC,CAAC;IAE9B;;;;;OAKG;gBACS,EAAC,KAAK,EAAE,OAAO,EAAC,EAAG;QAC3B,KAAK,CAAC,EAAG,MAAM,CAAC;QAChB,OAAO,CAAC,EAAG;YAAC,CAAC,GAAG,EAAC,MAAM,GAAG,GAAG,CAAA;SAAC,CAAC;KAClC;CAoBJ"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * You can implement your own logger. Crossauth only needs these functions
3
+ * and variables to be present.
4
+ */
5
+ export interface CrossauthLoggerInterface {
6
+ error(output: any): void;
7
+ warn(output: any): void;
8
+ info(output: any): void;
9
+ debug(output: any): void;
10
+ level?: number | string;
11
+ }
12
+ /**
13
+ *
14
+ * A very simple logging class with no dependencies.
15
+ *
16
+ * Logs to console.
17
+ *
18
+ * The logging API is designed so that you can replace this with other common loggers, eg Pino.
19
+ * To change it, use the global {@link setLogger} function. This has a parameter to tell
20
+ * Crossauth whether your logger accepts JSON input or not.
21
+ *
22
+ * When writing logs, we use the helper function {@link j} to send JSON to the logger if it is
23
+ * supprted, and a stringified JSON otherwise.
24
+ *
25
+ * <b>Crossauth logs<b>
26
+ *
27
+ * All Crossauth log messages are JSON (or stringified JSON, depending on whether the logger supports
28
+ * JSON input - this one does). The following fields may be present depending on context
29
+ * (`msg` is always present):
30
+ *
31
+ * - `msg` : main contents of the log
32
+ * - `err` : an error object. If a subclass of Error, it wil contain at least `message` and
33
+ * a stack trace in `stack`. If the error is of type{@link @crossauth/common!CrossauthError}
34
+ * it also will also contain `code` and `httpStatus`.
35
+ * - `hashedSessionCookie` : for security reasons, session cookies are not included in logs.
36
+ * However, so that errors can be correlated with each other, a hash
37
+ * of it is included in errors originating from a session.
38
+ * - `hashedCsrfCookie` : for security reasons, csrf cookies are not included in logs.
39
+ * However, so that errors can be correlated with each other, a hash
40
+ * of it is included in errors originating from a session.
41
+ * - `user` : username
42
+ * - `emailMessageId` : internal id of any email that is sent
43
+ * - `email` : email address
44
+ * - `userid` : sometimes provided in addition to username, or when username not available
45
+ * - `hahedApiKey` : a hash of an API key. The unhashed version is not logged for security,
46
+ * but a hash of it is logged for correlation purposes.
47
+ * - `header` : an HTTP header that relates to an error (eg `Authorization`), only if
48
+ * it is non-secret or invalid
49
+ * - `accessTokenHash` : hash of the JTI of an access token. For security reasons, the
50
+ * unhashed version is not logged.
51
+ * - `method`: request method (GET, PUT etc)
52
+ * - `url` : relevant URL
53
+ * - `ip` : relevant IP address
54
+ * - `scope` : OAuth scope
55
+ * - `errorCode` : Crossauth error code
56
+ * - `errorCodeName` : String version of Crossauth error code
57
+ * - `httpStatus` : HTTP status that will be returned
58
+ * - `port` port service is running on (only for starting a service)
59
+ * - `prefix` prefix for endpoints (only when starting a service)
60
+ * - `authorized` whether or not a valid OAuth access token was provided
61
+ *
62
+ */
63
+ export declare class CrossauthLogger {
64
+ /** Don't log anything */
65
+ static readonly None = 0;
66
+ /** Only log errors */
67
+ static readonly Error = 1;
68
+ /** Log errors and warning */
69
+ static readonly Warn = 2;
70
+ /** Log errors, warnings and info messages */
71
+ static readonly Info = 3;
72
+ /** Log everything */
73
+ static readonly Debug = 4;
74
+ /**
75
+ * Return the singleton instance of the logger.
76
+ * @returns the logger
77
+ */
78
+ static get logger(): CrossauthLoggerInterface;
79
+ /** the log level. This can be set dynamically */
80
+ level: 0 | 1 | 2 | 3 | 4;
81
+ static levelName: string[];
82
+ /**
83
+ * Create a logger with the given level
84
+ * @param level the level to report to
85
+ */
86
+ constructor(level?: 0 | 1 | 2 | 3 | 4);
87
+ setLevel(level: 0 | 1 | 2 | 3 | 4): void;
88
+ private log;
89
+ /**
90
+ * Report an error
91
+ * @param output object to output
92
+ */
93
+ error(output: any): void;
94
+ /**
95
+ * Report an warning
96
+ * @param output object to output
97
+ */
98
+ warn(output: any): void;
99
+ /**
100
+ * Report information
101
+ * @param output object to output
102
+ */
103
+ info(output: any): void;
104
+ /**
105
+ * Print a debugging message
106
+ * @param output object to output
107
+ */
108
+ debug(output: any): void;
109
+ /**
110
+ * Override the default logger.
111
+ *
112
+ * The only requirement is that the logger has the functions `error()`, `warn()`, `info()` and `debug()`.
113
+ * These functions must accept either an object or a string. If they can only accept a string,
114
+ * set `acceptsJson` to false.
115
+ *
116
+ * @param logger a new logger instance of any supported class
117
+ * @param acceptsJson set this to false if the logger can only take strings.
118
+ */
119
+ static setLogger(logger: CrossauthLoggerInterface, acceptsJson: boolean): void;
120
+ }
121
+ /**
122
+ * This is a helper function to allow you to use logger that either do or
123
+ * do not accept.
124
+ *
125
+ * If your logger does accept JSON (as defined in
126
+ * `globalThis.crossauthLoggerAcceptsJson`), this will return the object
127
+ * that was passed, including the stack trace in `stack` if the object
128
+ * passed in `err` is an exception. Otherwise, it returns a stringified
129
+ * version.
130
+ *
131
+ * All Crossauth error calls are made with this helper.
132
+ *
133
+ * @param arg put the key/value pairs you want to log in here. `err` will
134
+ * be treated as an `Error` instance if it is one, and a stack trace
135
+ * will be placed in `stack`.
136
+ * @returns either an object or a stringified JSON, depending on
137
+ * `globalThis.crossauthLoggerAcceptsJson`.
138
+ */
139
+ export declare function j(arg: {
140
+ [key: string]: any;
141
+ } | string): string | {
142
+ [key: string]: any;
143
+ };
144
+ declare global {
145
+ var crossauthLogger: CrossauthLoggerInterface;
146
+ var crossauthLoggerAcceptsJson: boolean;
147
+ }
148
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACrC,KAAK,CAAC,MAAM,EAAE,GAAG,GAAI,IAAI,CAAC;IAC1B,IAAI,CAAC,MAAM,EAAE,GAAG,GAAI,IAAI,CAAC;IACzB,IAAI,CAAC,MAAM,EAAE,GAAG,GAAI,IAAI,CAAC;IACzB,KAAK,CAAC,MAAM,EAAE,GAAG,GAAI,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAG,MAAM,GAAC,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,qBAAa,eAAe;IAGxB,yBAAyB;IACzB,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK;IAEzB,sBAAsB;IACtB,MAAM,CAAC,QAAQ,CAAC,KAAK,KAAK;IAE1B,6BAA6B;IAC7B,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK;IAEzB,6CAA6C;IAC7C,MAAM,CAAE,QAAQ,CAAC,IAAI,KAAK;IAE1B,qBAAqB;IACrB,MAAM,CAAC,QAAQ,CAAC,KAAK,KAAK;IAE1B;;;OAGG;IACH,MAAM,KAAK,MAAM,IAAK,wBAAwB,CAM7C;IAED,iDAAiD;IACjD,KAAK,EAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,CAAC,SAAS,WAA8C;IAE9D;;;OAGG;gBACS,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;IAerC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;IAIjC,OAAO,CAAC,GAAG;IAUX;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,GAAG;IAIjB;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,GAAG;IAIhB;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,GAAG;IAIhB;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,GAAG;IAIjB;;;;;;;;;OASG;IACH,MAAM,CAAC,SAAS,CAAC,MAAM,EAAG,wBAAwB,EAAE,WAAW,EAAG,OAAO;CAI5E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAG;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,GAAC,MAAM,GAAI,MAAM,GAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,CAUjF;AAED,OAAO,CAAC,MAAM,CAAC;IACX,IAAI,eAAe,EAAG,wBAAwB,CAAC;IAC/C,IAAI,0BAA0B,EAAG,OAAO,CAAC;CAC5C"}