@nymphjs/tilmeld 1.0.0-beta.11 → 1.0.0-beta.111
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/CHANGELOG.md +504 -0
- package/README.md +15 -2
- package/dist/AbleObject.d.ts +15 -0
- package/dist/AbleObject.js +18 -6
- package/dist/AbleObject.js.map +1 -1
- package/dist/Group.d.ts +182 -15
- package/dist/Group.js +571 -191
- package/dist/Group.js.map +1 -1
- package/dist/Group.test.js +86 -13
- package/dist/Group.test.js.map +1 -1
- package/dist/Tilmeld.d.ts +241 -12
- package/dist/Tilmeld.js +657 -257
- package/dist/Tilmeld.js.map +1 -1
- package/dist/Tilmeld.types.d.ts +5 -5
- package/dist/Tilmeld.types.js +1 -2
- package/dist/User.d.ts +396 -22
- package/dist/User.js +1386 -367
- package/dist/User.js.map +1 -1
- package/dist/User.test.js +133 -13
- package/dist/User.test.js.map +1 -1
- package/dist/conf/d.d.ts +306 -7
- package/dist/conf/d.js +1 -2
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +196 -141
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +2 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/enforceTilmeld.d.ts +3 -0
- package/dist/enforceTilmeld.js +18 -0
- package/dist/enforceTilmeld.js.map +1 -0
- package/dist/errors/AccessControlError.d.ts +2 -1
- package/dist/errors/AccessControlError.js +3 -6
- package/dist/errors/AccessControlError.js.map +1 -1
- package/dist/errors/BadDataError.d.ts +2 -1
- package/dist/errors/BadDataError.js +3 -6
- package/dist/errors/BadDataError.js.map +1 -1
- package/dist/errors/BadEmailError.d.ts +2 -1
- package/dist/errors/BadEmailError.js +3 -6
- package/dist/errors/BadEmailError.js.map +1 -1
- package/dist/errors/BadUsernameError.d.ts +2 -1
- package/dist/errors/BadUsernameError.js +3 -6
- package/dist/errors/BadUsernameError.js.map +1 -1
- package/dist/errors/CouldNotChangeDefaultPrimaryGroupError.js +1 -5
- package/dist/errors/CouldNotChangeDefaultPrimaryGroupError.js.map +1 -1
- package/dist/errors/EmailChangeRateLimitExceededError.js +1 -5
- package/dist/errors/EmailChangeRateLimitExceededError.js.map +1 -1
- package/dist/errors/index.d.ts +6 -6
- package/dist/errors/index.js +6 -22
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +17 -35
- package/dist/index.js.map +1 -1
- package/dist/testArtifacts.d.ts +19 -0
- package/dist/testArtifacts.js +920 -0
- package/dist/testArtifacts.js.map +1 -0
- package/dist/tilmeldJoiProps.d.ts +3 -3
- package/dist/tilmeldJoiProps.js +13 -18
- package/dist/tilmeldJoiProps.js.map +1 -1
- package/jest.config.js +11 -2
- package/package.json +32 -31
- package/src/AbleObject.ts +2 -2
- package/src/Group.test.ts +107 -6
- package/src/Group.ts +683 -224
- package/src/Tilmeld.ts +450 -262
- package/src/Tilmeld.types.ts +5 -5
- package/src/User.test.ts +163 -7
- package/src/User.ts +1628 -454
- package/src/conf/d.ts +83 -17
- package/src/conf/defaults.ts +172 -109
- package/src/conf/index.ts +2 -2
- package/src/enforceTilmeld.ts +20 -0
- package/src/errors/AccessControlError.ts +4 -2
- package/src/errors/BadDataError.ts +4 -2
- package/src/errors/BadEmailError.ts +4 -2
- package/src/errors/BadUsernameError.ts +4 -2
- package/src/errors/index.ts +6 -6
- package/src/index.ts +14 -10
- package/src/testArtifacts.ts +1485 -0
- package/src/tilmeldJoiProps.ts +8 -23
- package/src/type/locutus.d.ts +3 -0
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/src/Tilmeld.types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Group, { GroupData } from './Group';
|
|
2
|
-
import User, { UserData } from './User';
|
|
1
|
+
import Group, { GroupData } from './Group.js';
|
|
2
|
+
import User, { UserData } from './User.js';
|
|
3
3
|
|
|
4
4
|
export type AccessControlData = {
|
|
5
5
|
user?: User & UserData;
|
|
@@ -7,7 +7,7 @@ export type AccessControlData = {
|
|
|
7
7
|
acUser?: number;
|
|
8
8
|
acGroup?: number;
|
|
9
9
|
acOther?: number;
|
|
10
|
-
acFull?:
|
|
11
|
-
acWrite?:
|
|
12
|
-
acRead?:
|
|
10
|
+
acFull?: string[];
|
|
11
|
+
acWrite?: string[];
|
|
12
|
+
acRead?: string[];
|
|
13
13
|
};
|
package/src/User.test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { SQLite3Driver } from '@nymphjs/driver-sqlite3';
|
|
2
|
-
import { Nymph } from '@nymphjs/nymph';
|
|
2
|
+
import { Nymph, EntityUniqueConstraintError } from '@nymphjs/nymph';
|
|
3
3
|
|
|
4
|
-
import Tilmeld from './Tilmeld';
|
|
5
|
-
import defaults from './conf/defaults';
|
|
4
|
+
import Tilmeld from './Tilmeld.js';
|
|
5
|
+
import defaults from './conf/defaults.js';
|
|
6
|
+
import { AccessControlError } from './errors/index.js';
|
|
6
7
|
|
|
7
8
|
const tilmeld = new Tilmeld({
|
|
8
9
|
appName: 'My App',
|
|
@@ -11,17 +12,21 @@ const tilmeld = new Tilmeld({
|
|
|
11
12
|
cookiePath: '/',
|
|
12
13
|
setupPath: '/user',
|
|
13
14
|
emailUsernames: false,
|
|
15
|
+
domainSupport: true,
|
|
14
16
|
verifyRedirect: 'http://localhost:8080',
|
|
15
17
|
verifyChangeRedirect: 'http://localhost:8080',
|
|
16
18
|
cancelChangeRedirect: 'http://localhost:8080',
|
|
17
19
|
jwtSecret: 'shhhhh',
|
|
20
|
+
sendEmail: async (_tilmeld, _options, _user) => {
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
18
23
|
});
|
|
19
|
-
const
|
|
24
|
+
const nymph = new Nymph(
|
|
20
25
|
{},
|
|
21
26
|
new SQLite3Driver({
|
|
22
27
|
filename: ':memory:',
|
|
23
28
|
}),
|
|
24
|
-
tilmeld
|
|
29
|
+
tilmeld,
|
|
25
30
|
);
|
|
26
31
|
|
|
27
32
|
const User = tilmeld.User;
|
|
@@ -44,7 +49,7 @@ describe('User', () => {
|
|
|
44
49
|
const validUser = await makeNewUser();
|
|
45
50
|
|
|
46
51
|
expect(() => {
|
|
47
|
-
defaults.validatorUser(validUser);
|
|
52
|
+
defaults.validatorUser({ config: defaults } as Tilmeld, validUser);
|
|
48
53
|
}).not.toThrow();
|
|
49
54
|
});
|
|
50
55
|
|
|
@@ -55,7 +60,158 @@ describe('User', () => {
|
|
|
55
60
|
invalidUser.unknown = 'I should cause an error.';
|
|
56
61
|
|
|
57
62
|
expect(() => {
|
|
58
|
-
defaults.validatorUser(invalidUser);
|
|
63
|
+
defaults.validatorUser({ config: defaults } as Tilmeld, invalidUser);
|
|
59
64
|
}).toThrow('Invalid User: "unknown" is not allowed');
|
|
60
65
|
});
|
|
66
|
+
|
|
67
|
+
it("doesn't allow duplicate usernames", async () => {
|
|
68
|
+
const transaction = 'duplicate-usernames';
|
|
69
|
+
const tnymph = await nymph.startTransaction(transaction);
|
|
70
|
+
const TUser = tnymph.getEntityClass(User.class) as typeof User;
|
|
71
|
+
const newUserA = await TUser.factory();
|
|
72
|
+
|
|
73
|
+
newUserA.username = 'new-user';
|
|
74
|
+
newUserA.email = 'newusera@localhost';
|
|
75
|
+
newUserA.nameFirst = 'New';
|
|
76
|
+
newUserA.nameLast = 'User';
|
|
77
|
+
newUserA.name = 'New User';
|
|
78
|
+
newUserA.$password('password');
|
|
79
|
+
|
|
80
|
+
const newUserB = await TUser.factory();
|
|
81
|
+
|
|
82
|
+
newUserB.username = 'new-user';
|
|
83
|
+
newUserB.email = 'newuserb@localhost';
|
|
84
|
+
newUserB.nameFirst = 'New';
|
|
85
|
+
newUserB.nameLast = 'User';
|
|
86
|
+
newUserB.name = 'New User';
|
|
87
|
+
newUserB.$password('password');
|
|
88
|
+
|
|
89
|
+
const promises = [newUserA.$saveSkipAC(), newUserB.$saveSkipAC()];
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await Promise.all(promises);
|
|
93
|
+
|
|
94
|
+
throw new Error("Shouldn't get here because of unique constraint.");
|
|
95
|
+
} catch (e: any) {
|
|
96
|
+
expect(e).toBeInstanceOf(EntityUniqueConstraintError);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await Promise.allSettled(promises);
|
|
100
|
+
await tnymph.rollback(transaction);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("doesn't allow duplicate emails", async () => {
|
|
104
|
+
const transaction = 'duplicate-usernames';
|
|
105
|
+
const tnymph = await nymph.startTransaction(transaction);
|
|
106
|
+
const TUser = tnymph.getEntityClass(User.class) as typeof User;
|
|
107
|
+
const newUserA = await TUser.factory();
|
|
108
|
+
|
|
109
|
+
newUserA.username = 'new-user-a';
|
|
110
|
+
newUserA.email = 'newuser@localhost';
|
|
111
|
+
newUserA.nameFirst = 'New';
|
|
112
|
+
newUserA.nameLast = 'User';
|
|
113
|
+
newUserA.name = 'New User';
|
|
114
|
+
newUserA.$password('password');
|
|
115
|
+
|
|
116
|
+
const newUserB = await TUser.factory();
|
|
117
|
+
|
|
118
|
+
newUserB.username = 'new-user-b';
|
|
119
|
+
newUserB.email = 'newuser@localhost';
|
|
120
|
+
newUserB.nameFirst = 'New';
|
|
121
|
+
newUserB.nameLast = 'User';
|
|
122
|
+
newUserB.name = 'New User';
|
|
123
|
+
newUserB.$password('password');
|
|
124
|
+
|
|
125
|
+
const promises = [newUserA.$saveSkipAC(), newUserB.$saveSkipAC()];
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await Promise.all(promises);
|
|
129
|
+
|
|
130
|
+
throw new Error("Shouldn't get here because of unique constraint.");
|
|
131
|
+
} catch (e: any) {
|
|
132
|
+
expect(e).toBeInstanceOf(EntityUniqueConstraintError);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await Promise.allSettled(promises);
|
|
136
|
+
await tnymph.rollback(transaction);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('allows a domain user', async () => {
|
|
140
|
+
const domainAdmin = await User.factory();
|
|
141
|
+
|
|
142
|
+
domainAdmin.username = 'admin';
|
|
143
|
+
domainAdmin.email = 'admin@localhost';
|
|
144
|
+
domainAdmin.nameFirst = 'Admin';
|
|
145
|
+
domainAdmin.nameLast = 'User';
|
|
146
|
+
domainAdmin.name = 'Admin User';
|
|
147
|
+
domainAdmin.$password('password');
|
|
148
|
+
domainAdmin.$grant('tilmeld/domain/example.com/admin');
|
|
149
|
+
|
|
150
|
+
expect(await domainAdmin.$saveSkipAC()).toEqual(true);
|
|
151
|
+
|
|
152
|
+
// Log in the domain admin.
|
|
153
|
+
await tilmeld.fillSession(domainAdmin);
|
|
154
|
+
|
|
155
|
+
const domainUser = await User.factory();
|
|
156
|
+
|
|
157
|
+
domainUser.username = 'new-user@example.com';
|
|
158
|
+
domainUser.email = 'newuser@localhost';
|
|
159
|
+
domainUser.nameFirst = 'New';
|
|
160
|
+
domainUser.nameLast = 'User';
|
|
161
|
+
domainUser.name = 'New User';
|
|
162
|
+
domainUser.$password('password');
|
|
163
|
+
|
|
164
|
+
expect(await domainUser.$save()).toEqual(true);
|
|
165
|
+
|
|
166
|
+
tilmeld.clearSession();
|
|
167
|
+
|
|
168
|
+
for (const user of [domainAdmin, domainUser]) {
|
|
169
|
+
if (user.guid != null) {
|
|
170
|
+
expect(await user.$deleteSkipAC()).toEqual(true);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('disallows a domain user with no admin permission', async () => {
|
|
176
|
+
const domainAdmin = await User.factory();
|
|
177
|
+
|
|
178
|
+
domainAdmin.username = 'admin';
|
|
179
|
+
domainAdmin.email = 'admin@localhost';
|
|
180
|
+
domainAdmin.nameFirst = 'Admin';
|
|
181
|
+
domainAdmin.nameLast = 'User';
|
|
182
|
+
domainAdmin.name = 'Admin User';
|
|
183
|
+
domainAdmin.$password('password');
|
|
184
|
+
domainAdmin.$grant('tilmeld/domain/example.com/admin');
|
|
185
|
+
|
|
186
|
+
expect(await domainAdmin.$saveSkipAC()).toEqual(true);
|
|
187
|
+
|
|
188
|
+
// Log in the domain admin.
|
|
189
|
+
await tilmeld.fillSession(domainAdmin);
|
|
190
|
+
|
|
191
|
+
const domainUser = await User.factory();
|
|
192
|
+
|
|
193
|
+
// The wrong domain name.
|
|
194
|
+
domainUser.username = 'new-user@example.net';
|
|
195
|
+
domainUser.email = 'newuser@localhost';
|
|
196
|
+
domainUser.nameFirst = 'New';
|
|
197
|
+
domainUser.nameLast = 'User';
|
|
198
|
+
domainUser.name = 'New User';
|
|
199
|
+
domainUser.$password('password');
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
await domainUser.$save();
|
|
203
|
+
|
|
204
|
+
throw new Error("Shouldn't get here because of access control.");
|
|
205
|
+
} catch (e: any) {
|
|
206
|
+
expect(e).toBeInstanceOf(AccessControlError);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
tilmeld.clearSession();
|
|
210
|
+
|
|
211
|
+
for (const user of [domainAdmin, domainUser]) {
|
|
212
|
+
if (user.guid != null) {
|
|
213
|
+
expect(await user.$deleteSkipAC()).toEqual(true);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
61
217
|
});
|