@wtfalch/auth 0.15.0 → 0.16.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.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Whether a name somebody chose for themselves may be theirs here.
3
+ *
4
+ * The words are obscenity's English set plus names.list.ts, matched the way
5
+ * obscenity matches: look-alikes from other scripts become the Latin letter
6
+ * they imitate, numbers and symbols standing for letters become the letter
7
+ * (`n1gg3r`, `f4gg0t`, `$hit`), case is dropped and repeats collapse. Two
8
+ * matchers, because one cannot do both jobs: the STRICT one keeps the word
9
+ * boundaries obscenity's patterns rely on, so `cunt` is refused and
10
+ * `scunthorpe` is not; the LOOSE one skips everything that is not a letter and
11
+ * carries only the words that are slurs wherever they appear, so `n.i.g.g.e.r`
12
+ * and `xX_n1gg3r_Xx` are refused too. The strict one is shown the name in a
13
+ * few shapes -- as typed, split at case changes, with digits taken off the ends
14
+ * of its parts, and with its separators removed -- so `BigCunt`, `cunt69` and
15
+ * `c.u.n.t` are all one word to it.
16
+ *
17
+ * Reserved names are the ones that would let somebody pass as us or as a
18
+ * resource path, and the ones held for particular people (names.reserved.ts),
19
+ * compared on a flattened form so `adm1n` is as reserved as `admin`. A `1` is
20
+ * read as an `i` and as an `l`, so `wa1id` is `walid` too.
21
+ *
22
+ * The letter rules -- what characters, how long -- are the caller's: this is a
23
+ * login name in ZITADEL and one part of `name@tf.auth.wtfalch.dev`, so the
24
+ * default is ASCII letters, digits, `_`, `.` and `-`, three to thirty of them.
25
+ */
26
+ export type Refusal = 'too_short' | 'too_long' | 'characters' | 'reserved' | 'disallowed';
27
+ export type Verdict = {
28
+ ok: true;
29
+ } | {
30
+ ok: false;
31
+ reason: Refusal;
32
+ };
33
+ export interface NameRules {
34
+ minLength: number;
35
+ maxLength: number;
36
+ /** Tested against the name as typed. */
37
+ pattern: RegExp;
38
+ }
39
+ export declare const DEFAULT_RULES: NameRules;
40
+ /** The refusal as a sentence the person can act on. */
41
+ export declare function explain(reason: Refusal, rules?: NameRules): string;
42
+ export declare function checkName(name: string, rules?: NameRules): Verdict;
package/dist/names.js ADDED
@@ -0,0 +1,146 @@
1
+ import { DataSet, RegExpMatcher, collapseDuplicatesTransformer, englishDataset, englishRecommendedTransformers, parseRawPattern, resolveConfusablesTransformer, resolveLeetSpeakTransformer, skipNonAlphabeticTransformer, toAsciiLowerCaseTransformer, } from 'obscenity';
2
+ import reservedUsernames from 'reserved-usernames' with { type: 'json' };
3
+ import { NUMERIC, PHRASES, WHITELIST } from './names.list.js';
4
+ import { PEOPLE, SYSTEM } from './names.reserved.js';
5
+ export const DEFAULT_RULES = {
6
+ minLength: 3,
7
+ maxLength: 30,
8
+ pattern: /^[A-Za-z0-9][A-Za-z0-9._-]*$/,
9
+ };
10
+ const spellings = (entry) => [entry.word, ...(entry.also ?? [])];
11
+ /**
12
+ * Obscenity collapses repeated letters in the INPUT and matches the patterns
13
+ * as written, so a pattern has to be written the way its word looks after
14
+ * collapsing: `fitte` is met as `fite`. The English set allows two of a few
15
+ * letters (ni_gg_er, a_ss_); the loose matcher allows one of anything.
16
+ */
17
+ function collapsed(word, twice) {
18
+ return word.replace(/(.)\1+/g, (run, letter) => twice.includes(letter) ? run.slice(0, 2) : letter);
19
+ }
20
+ const ENGLISH_TWICE = 'beolsg';
21
+ /** Obscenity's English words and ours, with the boundaries each asks for. */
22
+ const strictWords = new DataSet().addAll(englishDataset);
23
+ for (const entry of PHRASES) {
24
+ strictWords.addPhrase((phrase) => {
25
+ phrase.setMetadata({ originalWord: entry.word });
26
+ for (const word of spellings(entry)) {
27
+ const written = collapsed(word, ENGLISH_TWICE);
28
+ phrase.addPattern(parseRawPattern(entry.anywhere ? written : `|${written}|`));
29
+ }
30
+ return phrase;
31
+ });
32
+ }
33
+ strictWords.addPhrase((phrase) => {
34
+ for (const term of WHITELIST)
35
+ phrase.addWhitelistedTerm(term);
36
+ return phrase;
37
+ });
38
+ const strict = new RegExpMatcher({ ...strictWords.build(), ...englishRecommendedTransformers });
39
+ /** Only the words that are slurs wherever they appear, read with everything between the letters skipped. */
40
+ const looseWords = new DataSet();
41
+ for (const entry of [
42
+ ...PHRASES.filter((entry) => entry.anywhere),
43
+ { word: 'nigger', also: ['nigga'] },
44
+ { word: 'kike' },
45
+ { word: 'retard' },
46
+ { word: 'tranny' },
47
+ ]) {
48
+ looseWords.addPhrase((phrase) => {
49
+ phrase.setMetadata({ originalWord: entry.word });
50
+ for (const word of spellings(entry))
51
+ phrase.addPattern(parseRawPattern(collapsed(word, '')));
52
+ return phrase;
53
+ });
54
+ }
55
+ const loose = new RegExpMatcher({
56
+ ...looseWords.build(),
57
+ blacklistMatcherTransformers: [
58
+ resolveConfusablesTransformer(),
59
+ resolveLeetSpeakTransformer(),
60
+ toAsciiLowerCaseTransformer(),
61
+ skipNonAlphabeticTransformer(),
62
+ collapseDuplicatesTransformer({ defaultThreshold: 1 }),
63
+ ],
64
+ });
65
+ /** What a digit or symbol stands for when it is standing for a letter. */
66
+ const LETTERS = {
67
+ '0': ['o'],
68
+ '1': ['i', 'l'],
69
+ '!': ['i', 'l'],
70
+ '|': ['i', 'l'],
71
+ '2': ['z'],
72
+ '3': ['e'],
73
+ '4': ['a'],
74
+ '@': ['a'],
75
+ '5': ['s'],
76
+ $: ['s'],
77
+ '6': ['g', 'b'],
78
+ '7': ['t'],
79
+ '8': ['b'],
80
+ '9': ['g'],
81
+ };
82
+ /**
83
+ * Lowercase letters with the digits read as letters and nothing else, runs
84
+ * collapsed. Every reading, since `1` may be an `i` or an `l`; the first is
85
+ * the one a list entry is stored under.
86
+ */
87
+ function flattenings(name) {
88
+ let forms = [''];
89
+ for (const char of name.toLowerCase()) {
90
+ const readings = /[a-z]/.test(char) ? [char] : (LETTERS[char] ?? []);
91
+ if (readings.length === 0)
92
+ continue;
93
+ // Bounded: a name of nothing but `1`s would otherwise double at every one.
94
+ const next = forms.length * readings.length > 64 ? readings.slice(0, 1) : readings;
95
+ forms = forms.flatMap((form) => next.map((letter) => form + letter));
96
+ }
97
+ return [...new Set(forms.map((form) => form.replace(/(.)\1+/g, '$1')))];
98
+ }
99
+ const reserved = new Set([...reservedUsernames, ...SYSTEM, ...PEOPLE].map((entry) => flattenings(entry)[0]));
100
+ /** The name in the shapes a word might hide in. */
101
+ function shapes(name) {
102
+ const parts = name.split(/[^A-Za-z0-9æøåÆØÅ]+/).filter(Boolean);
103
+ return [
104
+ name,
105
+ name.replace(/([a-zæøå])([A-ZÆØÅ])/g, '$1 $2'),
106
+ parts.map((part) => part.replace(/^\d+|\d+$/g, '')).join(' '),
107
+ parts.join(''),
108
+ ];
109
+ }
110
+ /** The refusal as a sentence the person can act on. */
111
+ export function explain(reason, rules = DEFAULT_RULES) {
112
+ switch (reason) {
113
+ case 'too_short':
114
+ return `A username needs at least ${rules.minLength} characters.`;
115
+ case 'too_long':
116
+ return `A username can have at most ${rules.maxLength} characters.`;
117
+ case 'characters':
118
+ return 'A username is letters, digits, dots, dashes and underscores, and starts with a letter or digit.';
119
+ case 'reserved':
120
+ return 'That username is reserved.';
121
+ case 'disallowed':
122
+ return 'That username is not allowed.';
123
+ }
124
+ }
125
+ export function checkName(name, rules = DEFAULT_RULES) {
126
+ const typed = name.trim();
127
+ if (typed.length < rules.minLength)
128
+ return { ok: false, reason: 'too_short' };
129
+ if (typed.length > rules.maxLength)
130
+ return { ok: false, reason: 'too_long' };
131
+ if (!rules.pattern.test(typed))
132
+ return { ok: false, reason: 'characters' };
133
+ const digitsKept = typed.toLowerCase().replace(/[^a-z0-9]/g, '');
134
+ if (NUMERIC.some((entry) => digitsKept.includes(entry)))
135
+ return { ok: false, reason: 'disallowed' };
136
+ if (loose.hasMatch(typed))
137
+ return { ok: false, reason: 'disallowed' };
138
+ if (shapes(typed).some((shape) => strict.hasMatch(shape))) {
139
+ return { ok: false, reason: 'disallowed' };
140
+ }
141
+ // Last, so that a number that means something (`14.88` reads as `lab`) is refused for what it is.
142
+ if (flattenings(typed).some((form) => reserved.has(form))) {
143
+ return { ok: false, reason: 'reserved' };
144
+ }
145
+ return { ok: true };
146
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * What obscenity's English set does not know, and what is ours. Edit freely.
3
+ *
4
+ * `anywhere` words are refused wherever they appear, however spelled -- so
5
+ * only words with no innocent containing word belong there; `coon` (raccoon)
6
+ * and `paki` (Pakistan) do not. The rest are refused as a whole name or as a
7
+ * part of one split at separators and case changes: `nazi` and `big_nazi`
8
+ * are out, `ashkenazi` is not. `also` lists other spellings of the same word.
9
+ */
10
+ export interface Entry {
11
+ word: string;
12
+ anywhere?: boolean;
13
+ also?: string[];
14
+ }
15
+ export declare const PHRASES: Entry[];
16
+ /** Innocent names obscenity's English patterns would otherwise catch. */
17
+ export declare const WHITELIST: string[];
18
+ /** Read on the name with its digits kept, for the things that are numbers. */
19
+ export declare const NUMERIC: string[];
@@ -0,0 +1,42 @@
1
+ export const PHRASES = [
2
+ // en, beyond obscenity's set
3
+ { word: 'faggot', anywhere: true },
4
+ { word: 'chink', anywhere: true },
5
+ { word: 'wetback', anywhere: true },
6
+ { word: 'raghead', anywhere: true },
7
+ { word: 'towelhead', anywhere: true },
8
+ { word: 'hitler', anywhere: true },
9
+ { word: 'gook' },
10
+ { word: 'spic' },
11
+ { word: 'coon' },
12
+ { word: 'paki' },
13
+ { word: 'nazi' },
14
+ { word: 'pedo', also: ['paedo', 'pedophile', 'paedophile'] },
15
+ { word: 'rapist' },
16
+ { word: 'homo' },
17
+ // no
18
+ { word: 'neger', anywhere: true },
19
+ { word: 'svarting', anywhere: true },
20
+ { word: 'sotrør', anywhere: true, also: ['sotror'] },
21
+ { word: 'morraknuller', anywhere: true },
22
+ { word: 'morrapuler', anywhere: true },
23
+ { word: 'pakkis' }, // collapsed to `pakis`, it would hide in pakistan; whole word only
24
+ { word: 'faen' },
25
+ { word: 'fitte' },
26
+ { word: 'kuk' },
27
+ { word: 'pikk' },
28
+ { word: 'hore' },
29
+ { word: 'ræva', also: ['raeva', 'reva'] },
30
+ { word: 'helvete' },
31
+ { word: 'jævla', also: ['jaevla', 'jevla', 'jævlig', 'jaevlig', 'jevlig'] },
32
+ { word: 'drittsekk' },
33
+ { word: 'soper' },
34
+ { word: 'homse' },
35
+ { word: 'mongo', also: ['mongis'] },
36
+ { word: 'tater' },
37
+ { word: 'sigøyner', also: ['sigoyner'] },
38
+ ];
39
+ /** Innocent names obscenity's English patterns would otherwise catch. */
40
+ export const WHITELIST = ['shiitake', 'fager'];
41
+ /** Read on the name with its digits kept, for the things that are numbers. */
42
+ export const NUMERIC = ['kkk', '1488'];
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Names nobody may choose. Edit freely; order and duplicates do not matter.
3
+ *
4
+ * Both lists are compared on a flattened form: lower case, digits and symbols
5
+ * read as the letters they stand for, repeated letters collapsed. So `adm1n`,
6
+ * `Admin`, `a.d.m.i.n` and `aadmin` are all `admin`, and `K4i` is `kai`.
7
+ *
8
+ * SYSTEM is every name that would let somebody pass as us, as the software,
9
+ * as a mailbox that means something, or as a path an app is likely to have.
10
+ * The `reserved-usernames` package is applied as well, so this list is the
11
+ * one we can read and vouch for rather than the only one.
12
+ *
13
+ * PEOPLE are names held for particular people. They are refused like the
14
+ * system ones, so the person they are held for gets them by being given
15
+ * them, not by racing for them.
16
+ */
17
+ export declare const SYSTEM: string[];
18
+ export declare const PEOPLE: string[];
@@ -0,0 +1,732 @@
1
+ /**
2
+ * Names nobody may choose. Edit freely; order and duplicates do not matter.
3
+ *
4
+ * Both lists are compared on a flattened form: lower case, digits and symbols
5
+ * read as the letters they stand for, repeated letters collapsed. So `adm1n`,
6
+ * `Admin`, `a.d.m.i.n` and `aadmin` are all `admin`, and `K4i` is `kai`.
7
+ *
8
+ * SYSTEM is every name that would let somebody pass as us, as the software,
9
+ * as a mailbox that means something, or as a path an app is likely to have.
10
+ * The `reserved-usernames` package is applied as well, so this list is the
11
+ * one we can read and vouch for rather than the only one.
12
+ *
13
+ * PEOPLE are names held for particular people. They are refused like the
14
+ * system ones, so the person they are held for gets them by being given
15
+ * them, not by racing for them.
16
+ */
17
+ export const SYSTEM = [
18
+ // Who runs the place
19
+ 'admin',
20
+ 'admins',
21
+ 'administrator',
22
+ 'administrators',
23
+ 'sysadmin',
24
+ 'sysop',
25
+ 'root',
26
+ 'superuser',
27
+ 'su',
28
+ 'sudo',
29
+ 'owner',
30
+ 'owners',
31
+ 'master',
32
+ 'manager',
33
+ 'managers',
34
+ 'management',
35
+ 'operator',
36
+ 'operators',
37
+ 'moderator',
38
+ 'moderators',
39
+ 'mod',
40
+ 'mods',
41
+ 'staff',
42
+ 'team',
43
+ 'teams',
44
+ 'crew',
45
+ 'official',
46
+ 'officials',
47
+ 'founder',
48
+ 'founders',
49
+ 'ceo',
50
+ 'cto',
51
+ 'cfo',
52
+ 'coo',
53
+ 'boss',
54
+ 'chief',
55
+ 'director',
56
+ 'employee',
57
+ 'employees',
58
+ 'agent',
59
+ 'agents',
60
+ 'representative',
61
+ 'rep',
62
+ 'verified',
63
+ 'trusted',
64
+ 'vip',
65
+ // The software and the machines
66
+ 'system',
67
+ 'sys',
68
+ 'daemon',
69
+ 'service',
70
+ 'services',
71
+ 'server',
72
+ 'servers',
73
+ 'host',
74
+ 'hosts',
75
+ 'hostname',
76
+ 'localhost',
77
+ 'local',
78
+ 'bot',
79
+ 'bots',
80
+ 'robot',
81
+ 'robots',
82
+ 'automation',
83
+ 'cron',
84
+ 'scheduler',
85
+ 'worker',
86
+ 'workers',
87
+ 'job',
88
+ 'jobs',
89
+ 'queue',
90
+ 'cache',
91
+ 'db',
92
+ 'database',
93
+ 'databases',
94
+ 'sql',
95
+ 'postgres',
96
+ 'postgresql',
97
+ 'redis',
98
+ 'backup',
99
+ 'backups',
100
+ 'storage',
101
+ 'bucket',
102
+ 'cdn',
103
+ 'static',
104
+ 'assets',
105
+ 'public',
106
+ 'private',
107
+ 'internal',
108
+ 'external',
109
+ 'default',
110
+ 'config',
111
+ 'configuration',
112
+ 'settings',
113
+ 'preferences',
114
+ 'options',
115
+ 'env',
116
+ 'environment',
117
+ 'dev',
118
+ 'development',
119
+ 'staging',
120
+ 'stage',
121
+ 'prod',
122
+ 'production',
123
+ 'test',
124
+ 'tests',
125
+ 'testing',
126
+ 'tester',
127
+ 'demo',
128
+ 'sandbox',
129
+ 'alpha',
130
+ 'beta',
131
+ 'preview',
132
+ 'canary',
133
+ 'nightly',
134
+ 'debug',
135
+ 'trace',
136
+ 'log',
137
+ 'logs',
138
+ 'metrics',
139
+ 'monitor',
140
+ 'monitoring',
141
+ 'health',
142
+ 'healthz',
143
+ 'healthcheck',
144
+ 'status',
145
+ 'ping',
146
+ 'uptime',
147
+ // The network and its protocols
148
+ 'www',
149
+ 'web',
150
+ 'http',
151
+ 'https',
152
+ 'ftp',
153
+ 'sftp',
154
+ 'ssh',
155
+ 'telnet',
156
+ 'dns',
157
+ 'ns',
158
+ 'mx',
159
+ 'vpn',
160
+ 'proxy',
161
+ 'gateway',
162
+ 'router',
163
+ 'firewall',
164
+ 'ip',
165
+ 'tcp',
166
+ 'udp',
167
+ 'smtp',
168
+ 'imap',
169
+ 'pop',
170
+ 'mail',
171
+ 'email',
172
+ 'emails',
173
+ 'e-mail',
174
+ 'mailer',
175
+ 'mailer-daemon',
176
+ 'mailbox',
177
+ 'inbox',
178
+ 'outbox',
179
+ 'postmaster',
180
+ 'hostmaster',
181
+ 'webmaster',
182
+ 'listmaster',
183
+ 'abuse',
184
+ 'noc',
185
+ 'security',
186
+ 'usenet',
187
+ 'news',
188
+ 'uucp',
189
+ 'noreply',
190
+ 'no-reply',
191
+ 'no_reply',
192
+ 'donotreply',
193
+ 'do-not-reply',
194
+ 'reply',
195
+ 'bounce',
196
+ 'bounces',
197
+ 'api',
198
+ 'apis',
199
+ 'graphql',
200
+ 'rest',
201
+ 'rpc',
202
+ 'grpc',
203
+ 'ws',
204
+ 'wss',
205
+ 'socket',
206
+ 'websocket',
207
+ 'webhook',
208
+ 'webhooks',
209
+ 'callback',
210
+ 'callbacks',
211
+ 'oauth',
212
+ 'oauth2',
213
+ 'oidc',
214
+ 'openid',
215
+ 'sso',
216
+ 'saml',
217
+ 'ldap',
218
+ 'auth',
219
+ 'authn',
220
+ 'authz',
221
+ 'authentication',
222
+ 'authorization',
223
+ 'authorize',
224
+ 'token',
225
+ 'tokens',
226
+ 'jwt',
227
+ 'key',
228
+ 'keys',
229
+ 'apikey',
230
+ 'secret',
231
+ 'secrets',
232
+ 'cert',
233
+ 'certs',
234
+ 'certificate',
235
+ 'ssl',
236
+ 'tls',
237
+ 'acme',
238
+ 'well-known',
239
+ 'robots.txt',
240
+ 'sitemap',
241
+ 'favicon',
242
+ 'manifest',
243
+ // Getting in and out
244
+ 'login',
245
+ 'logon',
246
+ 'logout',
247
+ 'logoff',
248
+ 'signin',
249
+ 'sign-in',
250
+ 'sign_in',
251
+ 'signout',
252
+ 'sign-out',
253
+ 'sign_out',
254
+ 'signup',
255
+ 'sign-up',
256
+ 'sign_up',
257
+ 'register',
258
+ 'registration',
259
+ 'unregister',
260
+ 'session',
261
+ 'sessions',
262
+ 'password',
263
+ 'passwords',
264
+ 'passwd',
265
+ 'pwd',
266
+ 'reset',
267
+ 'recover',
268
+ 'recovery',
269
+ 'forgot',
270
+ 'verify',
271
+ 'verification',
272
+ 'confirm',
273
+ 'confirmation',
274
+ 'activate',
275
+ 'activation',
276
+ 'deactivate',
277
+ 'invite',
278
+ 'invites',
279
+ 'invitation',
280
+ 'invitations',
281
+ 'join',
282
+ 'onboarding',
283
+ 'welcome',
284
+ 'account',
285
+ 'accounts',
286
+ 'profile',
287
+ 'profiles',
288
+ 'user',
289
+ 'users',
290
+ 'username',
291
+ 'usernames',
292
+ 'member',
293
+ 'members',
294
+ 'membership',
295
+ 'people',
296
+ 'person',
297
+ 'identity',
298
+ 'identities',
299
+ 'credential',
300
+ 'credentials',
301
+ // Pronouns and placeholders that read as somebody
302
+ 'me',
303
+ 'my',
304
+ 'mine',
305
+ 'myself',
306
+ 'self',
307
+ 'i',
308
+ 'you',
309
+ 'your',
310
+ 'yours',
311
+ 'yourself',
312
+ 'we',
313
+ 'us',
314
+ 'our',
315
+ 'ours',
316
+ 'they',
317
+ 'them',
318
+ 'their',
319
+ 'everyone',
320
+ 'everybody',
321
+ 'anyone',
322
+ 'anybody',
323
+ 'someone',
324
+ 'somebody',
325
+ 'nobody',
326
+ 'noone',
327
+ 'no-one',
328
+ 'all',
329
+ 'any',
330
+ 'none',
331
+ 'guest',
332
+ 'guests',
333
+ 'visitor',
334
+ 'anonymous',
335
+ 'anon',
336
+ 'unknown',
337
+ 'unnamed',
338
+ 'noname',
339
+ 'nobody',
340
+ 'null',
341
+ 'nil',
342
+ 'nan',
343
+ 'undefined',
344
+ 'void',
345
+ 'true',
346
+ 'false',
347
+ 'yes',
348
+ 'no',
349
+ 'ok',
350
+ 'example',
351
+ 'examples',
352
+ 'sample',
353
+ 'samples',
354
+ 'placeholder',
355
+ 'dummy',
356
+ 'foo',
357
+ 'bar',
358
+ 'baz',
359
+ 'tbd',
360
+ 'tba',
361
+ 'todo',
362
+ 'temp',
363
+ 'tmp',
364
+ 'deleted',
365
+ 'removed',
366
+ 'banned',
367
+ 'suspended',
368
+ 'disabled',
369
+ 'inactive',
370
+ 'blocked',
371
+ 'spam',
372
+ 'spammer',
373
+ 'junk',
374
+ 'trash',
375
+ 'fake',
376
+ 'scam',
377
+ // Mailboxes and departments people write to
378
+ 'info',
379
+ 'information',
380
+ 'contact',
381
+ 'contacts',
382
+ 'contactus',
383
+ 'contact-us',
384
+ 'hello',
385
+ 'hi',
386
+ 'hey',
387
+ 'help',
388
+ 'helpdesk',
389
+ 'support',
390
+ 'customerservice',
391
+ 'customer-service',
392
+ 'customercare',
393
+ 'service-desk',
394
+ 'servicedesk',
395
+ 'faq',
396
+ 'feedback',
397
+ 'complaints',
398
+ 'report',
399
+ 'reports',
400
+ 'sales',
401
+ 'marketing',
402
+ 'billing',
403
+ 'invoice',
404
+ 'invoices',
405
+ 'payment',
406
+ 'payments',
407
+ 'pay',
408
+ 'finance',
409
+ 'accounting',
410
+ 'legal',
411
+ 'privacy',
412
+ 'compliance',
413
+ 'hr',
414
+ 'careers',
415
+ 'recruiting',
416
+ 'press',
417
+ 'media',
418
+ 'pr',
419
+ 'partners',
420
+ 'partner',
421
+ 'partnership',
422
+ 'affiliate',
423
+ 'affiliates',
424
+ 'sponsor',
425
+ 'sponsors',
426
+ 'newsletter',
427
+ 'newsletters',
428
+ 'notification',
429
+ 'notifications',
430
+ 'alert',
431
+ 'alerts',
432
+ 'update',
433
+ 'updates',
434
+ 'announcement',
435
+ 'announcements',
436
+ 'digest',
437
+ 'subscribe',
438
+ 'unsubscribe',
439
+ 'subscription',
440
+ 'subscriptions',
441
+ // Pages an app is likely to have
442
+ 'home',
443
+ 'homepage',
444
+ 'index',
445
+ 'main',
446
+ 'app',
447
+ 'apps',
448
+ 'application',
449
+ 'applications',
450
+ 'dashboard',
451
+ 'console',
452
+ 'panel',
453
+ 'cpanel',
454
+ 'control',
455
+ 'about',
456
+ 'aboutus',
457
+ 'about-us',
458
+ 'terms',
459
+ 'tos',
460
+ 'terms-of-service',
461
+ 'policy',
462
+ 'policies',
463
+ 'cookie',
464
+ 'cookies',
465
+ 'imprint',
466
+ 'copyright',
467
+ 'license',
468
+ 'licenses',
469
+ 'licence',
470
+ 'dmca',
471
+ 'pricing',
472
+ 'price',
473
+ 'prices',
474
+ 'plan',
475
+ 'plans',
476
+ 'premium',
477
+ 'pro',
478
+ 'plus',
479
+ 'free',
480
+ 'upgrade',
481
+ 'downgrade',
482
+ 'checkout',
483
+ 'cart',
484
+ 'shop',
485
+ 'store',
486
+ 'order',
487
+ 'orders',
488
+ 'receipt',
489
+ 'refund',
490
+ 'refunds',
491
+ 'donate',
492
+ 'donation',
493
+ 'blog',
494
+ 'blogs',
495
+ 'article',
496
+ 'articles',
497
+ 'post',
498
+ 'posts',
499
+ 'page',
500
+ 'pages',
501
+ 'wiki',
502
+ 'doc',
503
+ 'docs',
504
+ 'documentation',
505
+ 'guide',
506
+ 'guides',
507
+ 'tutorial',
508
+ 'tutorials',
509
+ 'learn',
510
+ 'community',
511
+ 'agora',
512
+ 'forum',
513
+ 'forums',
514
+ 'chat',
515
+ 'chats',
516
+ 'message',
517
+ 'messages',
518
+ 'messaging',
519
+ 'dm',
520
+ 'search',
521
+ 'explore',
522
+ 'discover',
523
+ 'browse',
524
+ 'trending',
525
+ 'popular',
526
+ 'featured',
527
+ 'new',
528
+ 'latest',
529
+ 'top',
530
+ 'best',
531
+ 'recent',
532
+ 'random',
533
+ 'archive',
534
+ 'archives',
535
+ 'history',
536
+ 'activity',
537
+ 'event',
538
+ 'events',
539
+ 'calendar',
540
+ 'schedule',
541
+ 'task',
542
+ 'tasks',
543
+ 'project',
544
+ 'projects',
545
+ 'group',
546
+ 'groups',
547
+ 'organization',
548
+ 'organizations',
549
+ 'organisation',
550
+ 'organisations',
551
+ 'org',
552
+ 'orgs',
553
+ 'company',
554
+ 'companies',
555
+ 'enterprise',
556
+ 'business',
557
+ 'workspace',
558
+ 'workspaces',
559
+ 'site',
560
+ 'sites',
561
+ 'website',
562
+ 'portal',
563
+ 'hub',
564
+ 'center',
565
+ 'centre',
566
+ 'lab',
567
+ 'labs',
568
+ 'studio',
569
+ 'developer',
570
+ 'developers',
571
+ 'engineering',
572
+ 'design',
573
+ 'product',
574
+ 'products',
575
+ 'feature',
576
+ 'features',
577
+ 'roadmap',
578
+ 'changelog',
579
+ 'release',
580
+ 'releases',
581
+ 'version',
582
+ 'versions',
583
+ 'download',
584
+ 'downloads',
585
+ 'upload',
586
+ 'uploads',
587
+ 'file',
588
+ 'files',
589
+ 'image',
590
+ 'images',
591
+ 'img',
592
+ 'photo',
593
+ 'photos',
594
+ 'video',
595
+ 'videos',
596
+ 'audio',
597
+ 'music',
598
+ 'stream',
599
+ 'streams',
600
+ 'live',
601
+ 'play',
602
+ 'player',
603
+ 'game',
604
+ 'games',
605
+ 'install',
606
+ 'setup',
607
+ 'start',
608
+ 'getting-started',
609
+ 'connect',
610
+ 'share',
611
+ 'embed',
612
+ 'widget',
613
+ 'widgets',
614
+ 'plugin',
615
+ 'plugins',
616
+ 'extension',
617
+ 'extensions',
618
+ 'integration',
619
+ 'integrations',
620
+ 'marketplace',
621
+ 'tools',
622
+ 'resources',
623
+ 'library',
624
+ 'gallery',
625
+ 'stats',
626
+ 'statistics',
627
+ 'analytics',
628
+ 'insights',
629
+ 'export',
630
+ 'import',
631
+ 'sync',
632
+ 'print',
633
+ 'edit',
634
+ 'delete',
635
+ 'remove',
636
+ 'create',
637
+ 'add',
638
+ 'save',
639
+ 'cancel',
640
+ 'submit',
641
+ 'send',
642
+ 'error',
643
+ 'errors',
644
+ '404',
645
+ '500',
646
+ 'not-found',
647
+ 'notfound',
648
+ 'forbidden',
649
+ 'unauthorized',
650
+ // Us, and the software we run
651
+ 'tf',
652
+ 'offline',
653
+ 'the',
654
+ 'wtfalch',
655
+ 'tallis',
656
+ 'falch',
657
+ 'valet',
658
+ 'lokessmie',
659
+ 'proach',
660
+ 'zitadel',
661
+ 'coolify',
662
+ 'cloudflare',
663
+ 'resend',
664
+ // The same, in Norwegian
665
+ 'drift',
666
+ 'driftsansvarlig',
667
+ 'brukerstotte',
668
+ 'hjelp',
669
+ 'kundeservice',
670
+ 'kundestotte',
671
+ 'kontakt',
672
+ 'kontakt-oss',
673
+ 'kontaktoss',
674
+ 'post',
675
+ 'epost',
676
+ 'e-post',
677
+ 'nyheter',
678
+ 'nyhetsbrev',
679
+ 'personvern',
680
+ 'vilkar',
681
+ 'betaling',
682
+ 'faktura',
683
+ 'konto',
684
+ 'kontoer',
685
+ 'bruker',
686
+ 'brukere',
687
+ 'brukernavn',
688
+ 'innlogging',
689
+ 'logginn',
690
+ 'logg-inn',
691
+ 'loggut',
692
+ 'logg-ut',
693
+ 'registrer',
694
+ 'registrering',
695
+ 'passord',
696
+ 'sikkerhet',
697
+ 'ansatt',
698
+ 'ansatte',
699
+ 'ledelse',
700
+ 'leder',
701
+ 'eier',
702
+ 'sjef',
703
+ 'offisiell',
704
+ 'tjeneste',
705
+ 'tjenester',
706
+ 'hjem',
707
+ 'forside',
708
+ 'om',
709
+ 'om-oss',
710
+ 'omoss',
711
+ 'sok',
712
+ 'alle',
713
+ 'ingen',
714
+ 'gjest',
715
+ 'gjester',
716
+ 'anonym',
717
+ 'ukjent',
718
+ 'slettet',
719
+ 'sperret',
720
+ 'prove',
721
+ 'eksempel',
722
+ ];
723
+ export const PEOPLE = [
724
+ 'william',
725
+ 'kai',
726
+ 'alex',
727
+ 'walid',
728
+ 'odin',
729
+ 'audun',
730
+ 'peter',
731
+ 'anne',
732
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wtfalch/auth",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Sign in against auth.wtfalch.dev: a server session for a Next.js app, and a browser client with silent single sign-on across subdomains.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,6 +30,10 @@
30
30
  "types": "./dist/namespaces.d.ts",
31
31
  "default": "./dist/namespaces.js"
32
32
  },
33
+ "./names": {
34
+ "types": "./dist/names.d.ts",
35
+ "default": "./dist/names.js"
36
+ },
33
37
  "./namespace-server": {
34
38
  "types": "./dist/namespace-server.d.ts",
35
39
  "default": "./dist/namespace-server.js"
@@ -55,7 +59,9 @@
55
59
  },
56
60
  "dependencies": {
57
61
  "jose": "^6.2.10",
58
- "openid-client": "6.8.7"
62
+ "obscenity": "^0.4.6",
63
+ "openid-client": "6.8.7",
64
+ "reserved-usernames": "^1.1.6"
59
65
  },
60
66
  "peerDependencies": {
61
67
  "next": ">=15.0.0"