@gasboost/auth 0.4.0 → 0.5.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.
- package/README.md +43 -0
- package/dist/AppsScriptAuth.js +21 -17
- package/dist/AuthPattern.js +4 -1
- package/dist/api/AppsScriptAuthPassword.js +17 -13
- package/dist/api/AppsScriptAuthSession.js +5 -1
- package/dist/api/AppsScriptAuthSignIn.js +12 -8
- package/dist/api/AppsScriptAuthSignOut.js +5 -1
- package/dist/api/AppsScriptAuthSignUp.js +12 -8
- package/dist/api/SignIn.js +7 -3
- package/dist/api/SignUp.js +7 -3
- package/dist/authentication/AppsScriptAuthentication.js +11 -6
- package/dist/authentication/Authentication.js +2 -1
- package/dist/authentication/EmailPasswordAuthentication.js +13 -8
- package/dist/authorization/AppsScriptAuthorization.d.ts +33 -0
- package/dist/authorization/AppsScriptAuthorization.js +36 -0
- package/dist/authorization/AuthorizationPolicy.d.ts +32 -0
- package/dist/authorization/AuthorizationPolicy.js +63 -0
- package/dist/authorization/AuthorizationRepository.d.ts +13 -0
- package/dist/authorization/AuthorizationRepository.js +2 -0
- package/dist/authorization/index.d.ts +1 -0
- package/dist/authorization/index.js +5 -0
- package/dist/domain/Account.js +5 -1
- package/dist/domain/Errors.js +5 -1
- package/dist/domain/Password.js +7 -2
- package/dist/domain/PasswordCredential.js +18 -14
- package/dist/domain/PasswordReset.js +8 -4
- package/dist/domain/PasswordResetToken.js +5 -1
- package/dist/domain/Session.js +5 -1
- package/dist/domain/User.js +5 -1
- package/dist/factory/sessionStorageFactory.js +8 -5
- package/dist/hooks/AuthHooks.js +2 -1
- package/dist/identity/AppsScriptIdentity.js +7 -3
- package/dist/identity/EmailPasswordIdentity.js +7 -3
- package/dist/identity/ProviderIdentity.js +2 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +28 -10
- package/dist/registration/AppsScriptRegistration.js +13 -9
- package/dist/registration/EmailPasswordRegistration.js +15 -11
- package/dist/registration/Registration.js +2 -1
- package/dist/schema/AuthSchema.js +4 -1
- package/dist/schema/AuthorizationSchema.d.ts +64 -0
- package/dist/schema/AuthorizationSchema.js +24 -0
- package/dist/schema/createAuthTables.js +22 -19
- package/dist/schema/createAuthorizationTables.d.ts +25 -0
- package/dist/schema/createAuthorizationTables.js +43 -0
- package/dist/storage/AppsScriptAuthRepository.js +2 -1
- package/dist/storage/AppsScriptCacheSessionStorage.js +7 -3
- package/dist/storage/AppsScriptPropertiesSessionStorage.js +8 -4
- package/dist/storage/AppsScriptSessionStorage.js +2 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -90,6 +90,49 @@ const repository: AppsScriptAuthRepository = {
|
|
|
90
90
|
|
|
91
91
|
将来的に SheetORM 向け adapter は auth-core とは別 package として提供する想定です。
|
|
92
92
|
|
|
93
|
+
## Authorization
|
|
94
|
+
|
|
95
|
+
アプリケーション内部の認可には、GAS runtime に依存しない `AuthorizationPolicy` と、Backend service の `AppsScriptAuthorization` を利用できます。
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import {
|
|
99
|
+
AppsScriptAuthorization,
|
|
100
|
+
createAuthorizationTables,
|
|
101
|
+
} from "@gasboost/auth";
|
|
102
|
+
import { AuthorizationPolicy } from "@gasboost/auth/authorization";
|
|
103
|
+
|
|
104
|
+
export const authorizationPolicy = new AuthorizationPolicy({
|
|
105
|
+
project: ["read", "create", "update", "delete"],
|
|
106
|
+
authorization: ["manage"],
|
|
107
|
+
} as const)
|
|
108
|
+
.linkRole("admin", {
|
|
109
|
+
project: ["read", "create", "update", "delete"],
|
|
110
|
+
authorization: ["manage"],
|
|
111
|
+
})
|
|
112
|
+
.linkRole("member", {
|
|
113
|
+
project: ["read"],
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const authorizationTables = createAuthorizationTables();
|
|
117
|
+
|
|
118
|
+
const authorization = new AppsScriptAuthorization({
|
|
119
|
+
policy: authorizationPolicy,
|
|
120
|
+
repository: authorizationRepository,
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`@gasboost/auth/authorization` は pure な subpath export です。Frontend / shared code では `AuthorizationPolicy` だけを import し、Backend で取得した effective permissions の表示制御に同じ `can()` を使えます。
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
const permissions = await authorization.resolve(session.userId);
|
|
128
|
+
|
|
129
|
+
authorizationPolicy.can(permissions, {
|
|
130
|
+
project: ["update"],
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Role definition と permission vocabulary は application code が source of truth です。Repository には assignment だけを保存し、未知の role / permission は grant せず fail closed になります。
|
|
135
|
+
|
|
93
136
|
## Initialize
|
|
94
137
|
|
|
95
138
|
`AppsScriptAuth` に Repository、GAS runtime、Session 設定、認証方式の設定を渡します。
|
package/dist/AppsScriptAuth.js
CHANGED
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuth = void 0;
|
|
4
|
+
const AppsScriptAuthPassword_1 = require("./api/AppsScriptAuthPassword");
|
|
5
|
+
const AppsScriptAuthSession_1 = require("./api/AppsScriptAuthSession");
|
|
6
|
+
const AppsScriptAuthSignIn_1 = require("./api/AppsScriptAuthSignIn");
|
|
7
|
+
const AppsScriptAuthSignOut_1 = require("./api/AppsScriptAuthSignOut");
|
|
8
|
+
const AppsScriptAuthSignUp_1 = require("./api/AppsScriptAuthSignUp");
|
|
9
|
+
const AppsScriptAuthentication_1 = require("./authentication/AppsScriptAuthentication");
|
|
10
|
+
const EmailPasswordAuthentication_1 = require("./authentication/EmailPasswordAuthentication");
|
|
11
|
+
const sessionStorageFactory_1 = require("./factory/sessionStorageFactory");
|
|
12
|
+
class AppsScriptAuth {
|
|
10
13
|
signIn;
|
|
11
14
|
signUp;
|
|
12
15
|
session;
|
|
13
16
|
signOut;
|
|
14
17
|
password;
|
|
15
18
|
constructor({ repository, session, runtime, emailPassword, appsScript, hooks, }) {
|
|
16
|
-
const sessionStorage = sessionStorageFactory(session.storageType, {
|
|
19
|
+
const sessionStorage = (0, sessionStorageFactory_1.sessionStorageFactory)(session.storageType, {
|
|
17
20
|
cacheService: runtime.cacheService,
|
|
18
21
|
propertiesService: runtime.propertiesService,
|
|
19
22
|
});
|
|
20
23
|
const expiresIn = session.expiresIn ?? 60 * 20;
|
|
21
24
|
const emailPasswordConfig = emailPassword
|
|
22
|
-
? new EmailPasswordAuthConfig(emailPassword)
|
|
25
|
+
? new EmailPasswordAuthentication_1.EmailPasswordAuthConfig(emailPassword)
|
|
23
26
|
: undefined;
|
|
24
27
|
const appsScriptConfig = appsScript
|
|
25
|
-
? new AppsScriptAuthenticationConfig(appsScript)
|
|
28
|
+
? new AppsScriptAuthentication_1.AppsScriptAuthenticationConfig(appsScript)
|
|
26
29
|
: undefined;
|
|
27
|
-
this.signIn = new AppsScriptAuthSignIn({
|
|
30
|
+
this.signIn = new AppsScriptAuthSignIn_1.AppsScriptAuthSignIn({
|
|
28
31
|
sessionStorage,
|
|
29
32
|
repository,
|
|
30
33
|
emailPassword: emailPasswordConfig,
|
|
@@ -38,7 +41,7 @@ export class AppsScriptAuth {
|
|
|
38
41
|
}
|
|
39
42
|
: {}),
|
|
40
43
|
});
|
|
41
|
-
this.signUp = new AppsScriptAuthSignUp({
|
|
44
|
+
this.signUp = new AppsScriptAuthSignUp_1.AppsScriptAuthSignUp({
|
|
42
45
|
sessionStorage,
|
|
43
46
|
expiresIn,
|
|
44
47
|
repository,
|
|
@@ -47,12 +50,12 @@ export class AppsScriptAuth {
|
|
|
47
50
|
utilities: runtime.utilities,
|
|
48
51
|
session: runtime.session,
|
|
49
52
|
});
|
|
50
|
-
this.session = new AppsScriptAuthSession({
|
|
53
|
+
this.session = new AppsScriptAuthSession_1.AppsScriptAuthSession({
|
|
51
54
|
sessionStorage,
|
|
52
55
|
});
|
|
53
|
-
this.signOut = new AppsScriptAuthSignOut(sessionStorage);
|
|
56
|
+
this.signOut = new AppsScriptAuthSignOut_1.AppsScriptAuthSignOut(sessionStorage);
|
|
54
57
|
this.password = (emailPasswordConfig?.passwordReset
|
|
55
|
-
? new AppsScriptAuthPassword({
|
|
58
|
+
? new AppsScriptAuthPassword_1.AppsScriptAuthPassword({
|
|
56
59
|
repository,
|
|
57
60
|
utilities: runtime.utilities,
|
|
58
61
|
emailPassword: emailPasswordConfig,
|
|
@@ -60,3 +63,4 @@ export class AppsScriptAuth {
|
|
|
60
63
|
: undefined);
|
|
61
64
|
}
|
|
62
65
|
}
|
|
66
|
+
exports.AppsScriptAuth = AppsScriptAuth;
|
package/dist/AuthPattern.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthPassword = void 0;
|
|
4
|
+
const AuthPattern_1 = require("../AuthPattern");
|
|
5
|
+
const Errors_1 = require("../domain/Errors");
|
|
6
|
+
const Password_1 = require("../domain/Password");
|
|
7
|
+
const PasswordCredential_1 = require("../domain/PasswordCredential");
|
|
8
|
+
const PasswordResetToken_1 = require("../domain/PasswordResetToken");
|
|
9
|
+
const EmailPasswordIdentity_1 = require("../identity/EmailPasswordIdentity");
|
|
10
|
+
class AppsScriptAuthPassword {
|
|
8
11
|
repository;
|
|
9
12
|
utilities;
|
|
10
13
|
emailPassword;
|
|
@@ -24,16 +27,16 @@ export class AppsScriptAuthPassword {
|
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
async forgot({ email }) {
|
|
27
|
-
const account = await this.repository.account.findByIdentity(authPattern.emailPassword, email);
|
|
30
|
+
const account = await this.repository.account.findByIdentity(AuthPattern_1.authPattern.emailPassword, email);
|
|
28
31
|
if (account === null) {
|
|
29
32
|
return;
|
|
30
33
|
}
|
|
31
|
-
if (!(account.identity instanceof EmailPasswordIdentity)) {
|
|
34
|
+
if (!(account.identity instanceof EmailPasswordIdentity_1.EmailPasswordIdentity)) {
|
|
32
35
|
throw new Error("Invalid account identity");
|
|
33
36
|
}
|
|
34
37
|
const now = new Date();
|
|
35
38
|
const expiresAt = new Date(now.getTime() + this.config.expiresIn * 1000);
|
|
36
|
-
const { credential, token } = PasswordCredential.generate({
|
|
39
|
+
const { credential, token } = PasswordCredential_1.PasswordCredential.generate({
|
|
37
40
|
account,
|
|
38
41
|
utilities: this.utilities,
|
|
39
42
|
expiresAt,
|
|
@@ -46,12 +49,12 @@ export class AppsScriptAuthPassword {
|
|
|
46
49
|
});
|
|
47
50
|
}
|
|
48
51
|
async reset({ token, newPassword, }) {
|
|
49
|
-
const passwordResetToken = new PasswordResetToken(token);
|
|
52
|
+
const passwordResetToken = new PasswordResetToken_1.PasswordResetToken(token);
|
|
50
53
|
const credential = await this.repository.passwordCredential.findByResetTokenHash(passwordResetToken.hash(this.utilities));
|
|
51
54
|
if (credential === null) {
|
|
52
|
-
throw new InvalidPasswordResetError();
|
|
55
|
+
throw new Errors_1.InvalidPasswordResetError();
|
|
53
56
|
}
|
|
54
|
-
const password = new Password(newPassword, this.utilities, this.emailPassword.pepper, this.emailPassword.iterations);
|
|
57
|
+
const password = new Password_1.Password(newPassword, this.utilities, this.emailPassword.pepper, this.emailPassword.iterations);
|
|
55
58
|
const hashedPassword = await password.hash(credential.account.id);
|
|
56
59
|
const updatedCredential = credential.resetPassword({
|
|
57
60
|
token,
|
|
@@ -62,3 +65,4 @@ export class AppsScriptAuthPassword {
|
|
|
62
65
|
await this.repository.passwordCredential.save(updatedCredential);
|
|
63
66
|
}
|
|
64
67
|
}
|
|
68
|
+
exports.AppsScriptAuthPassword = AppsScriptAuthPassword;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthSession = void 0;
|
|
4
|
+
class AppsScriptAuthSession {
|
|
2
5
|
sessionStorage;
|
|
3
6
|
constructor({ sessionStorage, }) {
|
|
4
7
|
this.sessionStorage = sessionStorage;
|
|
@@ -15,3 +18,4 @@ export class AppsScriptAuthSession {
|
|
|
15
18
|
await this.sessionStorage.cleanupExpired();
|
|
16
19
|
}
|
|
17
20
|
}
|
|
21
|
+
exports.AppsScriptAuthSession = AppsScriptAuthSession;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthSignIn = void 0;
|
|
4
|
+
const AppsScriptAuthentication_1 = require("../authentication/AppsScriptAuthentication");
|
|
5
|
+
const EmailPasswordAuthentication_1 = require("../authentication/EmailPasswordAuthentication");
|
|
6
|
+
const SignIn_1 = require("./SignIn");
|
|
7
|
+
class AppsScriptAuthSignIn {
|
|
5
8
|
email;
|
|
6
9
|
appsScript;
|
|
7
10
|
constructor({ sessionStorage, expiresIn, repository, emailPassword, appsScript, session, utilities, afterSignIn, }) {
|
|
@@ -10,9 +13,9 @@ export class AppsScriptAuthSignIn {
|
|
|
10
13
|
throw new Error("Email and password authentication is disabled");
|
|
11
14
|
}
|
|
12
15
|
emailPassword.ensureSignInEnabled();
|
|
13
|
-
const emailSignIn = new SignIn({
|
|
16
|
+
const emailSignIn = new SignIn_1.SignIn({
|
|
14
17
|
sessionStorage,
|
|
15
|
-
authentication: new EmailPasswordAuthentication(repository, utilities, emailPassword),
|
|
18
|
+
authentication: new EmailPasswordAuthentication_1.EmailPasswordAuthentication(repository, utilities, emailPassword),
|
|
16
19
|
utilities,
|
|
17
20
|
expiresIn,
|
|
18
21
|
...(afterSignIn
|
|
@@ -28,9 +31,9 @@ export class AppsScriptAuthSignIn {
|
|
|
28
31
|
throw new Error("Apps Script authentication is disabled");
|
|
29
32
|
}
|
|
30
33
|
appsScript.ensureSignInEnabled();
|
|
31
|
-
return new SignIn({
|
|
34
|
+
return new SignIn_1.SignIn({
|
|
32
35
|
sessionStorage,
|
|
33
|
-
authentication: new AppsScriptAuthentication(repository, session),
|
|
36
|
+
authentication: new AppsScriptAuthentication_1.AppsScriptAuthentication(repository, session),
|
|
34
37
|
utilities,
|
|
35
38
|
expiresIn,
|
|
36
39
|
...(afterSignIn
|
|
@@ -42,3 +45,4 @@ export class AppsScriptAuthSignIn {
|
|
|
42
45
|
};
|
|
43
46
|
}
|
|
44
47
|
}
|
|
48
|
+
exports.AppsScriptAuthSignIn = AppsScriptAuthSignIn;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthSignOut = void 0;
|
|
4
|
+
class AppsScriptAuthSignOut {
|
|
2
5
|
sessionStorage;
|
|
3
6
|
constructor(sessionStorage) {
|
|
4
7
|
this.sessionStorage = sessionStorage;
|
|
@@ -7,3 +10,4 @@ export class AppsScriptAuthSignOut {
|
|
|
7
10
|
await this.sessionStorage.delete(sessionId);
|
|
8
11
|
}
|
|
9
12
|
}
|
|
13
|
+
exports.AppsScriptAuthSignOut = AppsScriptAuthSignOut;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthSignUp = void 0;
|
|
4
|
+
const AppsScriptRegistration_1 = require("../registration/AppsScriptRegistration");
|
|
5
|
+
const EmailPasswordRegistration_1 = require("../registration/EmailPasswordRegistration");
|
|
6
|
+
const SignUp_1 = require("./SignUp");
|
|
7
|
+
class AppsScriptAuthSignUp {
|
|
5
8
|
email;
|
|
6
9
|
appsScript;
|
|
7
10
|
constructor({ sessionStorage, expiresIn, repository, emailPassword, appsScript, utilities, session, }) {
|
|
@@ -10,10 +13,10 @@ export class AppsScriptAuthSignUp {
|
|
|
10
13
|
throw new Error("Email and password authentication is disabled");
|
|
11
14
|
}
|
|
12
15
|
emailPassword.ensureSignUpEnabled();
|
|
13
|
-
const emailSignUp = new SignUp({
|
|
16
|
+
const emailSignUp = new SignUp_1.SignUp({
|
|
14
17
|
sessionStorage,
|
|
15
18
|
expiresIn,
|
|
16
|
-
registration: new EmailPasswordRegistration(repository, utilities, emailPassword),
|
|
19
|
+
registration: new EmailPasswordRegistration_1.EmailPasswordRegistration(repository, utilities, emailPassword),
|
|
17
20
|
utilities,
|
|
18
21
|
});
|
|
19
22
|
return emailSignUp.execute(input);
|
|
@@ -23,13 +26,14 @@ export class AppsScriptAuthSignUp {
|
|
|
23
26
|
throw new Error("Apps Script authentication is disabled");
|
|
24
27
|
}
|
|
25
28
|
appsScript.ensureSignUpEnabled();
|
|
26
|
-
const appsScriptSignUp = new SignUp({
|
|
29
|
+
const appsScriptSignUp = new SignUp_1.SignUp({
|
|
27
30
|
sessionStorage,
|
|
28
31
|
expiresIn,
|
|
29
|
-
registration: new AppsScriptRegistration(utilities, session, repository),
|
|
32
|
+
registration: new AppsScriptRegistration_1.AppsScriptRegistration(utilities, session, repository),
|
|
30
33
|
utilities,
|
|
31
34
|
});
|
|
32
35
|
return appsScriptSignUp.execute(input);
|
|
33
36
|
};
|
|
34
37
|
}
|
|
35
38
|
}
|
|
39
|
+
exports.AppsScriptAuthSignUp = AppsScriptAuthSignUp;
|
package/dist/api/SignIn.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SignIn = void 0;
|
|
4
|
+
const Session_1 = require("../domain/Session");
|
|
5
|
+
class SignIn {
|
|
3
6
|
sessionStorage;
|
|
4
7
|
expiresIn;
|
|
5
8
|
utilities;
|
|
@@ -14,7 +17,7 @@ export class SignIn {
|
|
|
14
17
|
}
|
|
15
18
|
async execute(credential) {
|
|
16
19
|
const user = await this.authentication.verify(credential);
|
|
17
|
-
const session = new Session({
|
|
20
|
+
const session = new Session_1.Session({
|
|
18
21
|
id: this.utilities.getUuid(),
|
|
19
22
|
userId: user.id,
|
|
20
23
|
createdAt: new Date(),
|
|
@@ -50,3 +53,4 @@ export class SignIn {
|
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
}
|
|
56
|
+
exports.SignIn = SignIn;
|
package/dist/api/SignUp.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SignUp = void 0;
|
|
4
|
+
const Session_1 = require("../domain/Session");
|
|
5
|
+
class SignUp {
|
|
3
6
|
sessionStorage;
|
|
4
7
|
registration;
|
|
5
8
|
utilities;
|
|
@@ -13,7 +16,7 @@ export class SignUp {
|
|
|
13
16
|
async execute(input) {
|
|
14
17
|
const user = await this.registration.register(input);
|
|
15
18
|
const now = new Date();
|
|
16
|
-
const session = new Session({
|
|
19
|
+
const session = new Session_1.Session({
|
|
17
20
|
id: this.utilities.getUuid(),
|
|
18
21
|
userId: user.id,
|
|
19
22
|
createdAt: now,
|
|
@@ -23,3 +26,4 @@ export class SignUp {
|
|
|
23
26
|
return { user, session };
|
|
24
27
|
}
|
|
25
28
|
}
|
|
29
|
+
exports.SignUp = SignUp;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthentication = exports.AppsScriptAuthenticationConfig = void 0;
|
|
4
|
+
const AuthPattern_1 = require("../AuthPattern");
|
|
5
|
+
const AppsScriptIdentity_1 = require("../identity/AppsScriptIdentity");
|
|
6
|
+
class AppsScriptAuthenticationConfig {
|
|
4
7
|
enabled;
|
|
5
8
|
isSignupEnabled;
|
|
6
9
|
constructor({ enabled = false, isSignupEnabled = true, }) {
|
|
@@ -19,7 +22,8 @@ export class AppsScriptAuthenticationConfig {
|
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
|
-
|
|
25
|
+
exports.AppsScriptAuthenticationConfig = AppsScriptAuthenticationConfig;
|
|
26
|
+
class AppsScriptAuthentication {
|
|
23
27
|
repository;
|
|
24
28
|
session;
|
|
25
29
|
constructor(repository, session) {
|
|
@@ -31,11 +35,11 @@ export class AppsScriptAuthentication {
|
|
|
31
35
|
if (!email) {
|
|
32
36
|
throw new Error("No active user found");
|
|
33
37
|
}
|
|
34
|
-
const account = await this.repository.account.findByIdentity(authPattern.appsScript, email);
|
|
38
|
+
const account = await this.repository.account.findByIdentity(AuthPattern_1.authPattern.appsScript, email);
|
|
35
39
|
if (!account) {
|
|
36
40
|
throw new Error("Account not found");
|
|
37
41
|
}
|
|
38
|
-
if (!(account.identity instanceof AppsScriptIdentity)) {
|
|
42
|
+
if (!(account.identity instanceof AppsScriptIdentity_1.AppsScriptIdentity)) {
|
|
39
43
|
throw new Error("Invalid identity");
|
|
40
44
|
}
|
|
41
45
|
const user = await this.repository.user.find(account.userId);
|
|
@@ -45,3 +49,4 @@ export class AppsScriptAuthentication {
|
|
|
45
49
|
return user;
|
|
46
50
|
}
|
|
47
51
|
}
|
|
52
|
+
exports.AppsScriptAuthentication = AppsScriptAuthentication;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EmailPasswordAuthentication = exports.EmailPasswordAuthConfig = void 0;
|
|
4
|
+
const AuthPattern_1 = require("../AuthPattern");
|
|
5
|
+
const Password_1 = require("../domain/Password");
|
|
6
|
+
const EmailPasswordIdentity_1 = require("../identity/EmailPasswordIdentity");
|
|
7
|
+
class EmailPasswordAuthConfig {
|
|
5
8
|
static DEFAULT_ITERATIONS = 300;
|
|
6
9
|
static MAX_ITERATIONS = 1000;
|
|
7
10
|
enabled;
|
|
@@ -45,7 +48,8 @@ export class EmailPasswordAuthConfig {
|
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
|
-
|
|
51
|
+
exports.EmailPasswordAuthConfig = EmailPasswordAuthConfig;
|
|
52
|
+
class EmailPasswordAuthentication {
|
|
49
53
|
repository;
|
|
50
54
|
utilities;
|
|
51
55
|
config;
|
|
@@ -55,14 +59,14 @@ export class EmailPasswordAuthentication {
|
|
|
55
59
|
this.config = config;
|
|
56
60
|
}
|
|
57
61
|
async verify(credential) {
|
|
58
|
-
const account = await this.repository.account.findByIdentity(authPattern.emailPassword, credential.email);
|
|
62
|
+
const account = await this.repository.account.findByIdentity(AuthPattern_1.authPattern.emailPassword, credential.email);
|
|
59
63
|
if (!account) {
|
|
60
64
|
throw new Error("Account not found");
|
|
61
65
|
}
|
|
62
|
-
if (!(account.identity instanceof EmailPasswordIdentity)) {
|
|
66
|
+
if (!(account.identity instanceof EmailPasswordIdentity_1.EmailPasswordIdentity)) {
|
|
63
67
|
throw new Error("Invalid identity");
|
|
64
68
|
}
|
|
65
|
-
const password = new Password(credential.password, this.utilities, this.config.pepper, this.config.iterations);
|
|
69
|
+
const password = new Password_1.Password(credential.password, this.utilities, this.config.pepper, this.config.iterations);
|
|
66
70
|
if (!(await account.identity.verify(password, account.id))) {
|
|
67
71
|
throw new Error("Invalid password");
|
|
68
72
|
}
|
|
@@ -73,3 +77,4 @@ export class EmailPasswordAuthentication {
|
|
|
73
77
|
return user;
|
|
74
78
|
}
|
|
75
79
|
}
|
|
80
|
+
exports.EmailPasswordAuthentication = EmailPasswordAuthentication;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AuthorizationPolicy, EffectivePermissions, PermissionOf, PermissionRequirement, PermissionStatement } from "./AuthorizationPolicy";
|
|
2
|
+
import type { AuthorizationRepository } from "./AuthorizationRepository";
|
|
3
|
+
type PolicyStatement<TPolicy> = TPolicy extends AuthorizationPolicy<infer TStatement, string> ? TStatement : never;
|
|
4
|
+
type PolicyRole<TPolicy> = TPolicy extends {
|
|
5
|
+
readonly $types: {
|
|
6
|
+
readonly role: infer TRole;
|
|
7
|
+
};
|
|
8
|
+
} ? Extract<TRole, string> : never;
|
|
9
|
+
type PolicyPermission<TPolicy> = TPolicy extends {
|
|
10
|
+
readonly $types: {
|
|
11
|
+
readonly permission: infer TPermission;
|
|
12
|
+
};
|
|
13
|
+
} ? Extract<TPermission, string> : never;
|
|
14
|
+
export declare class AppsScriptAuthorization<TPolicy extends AuthorizationPolicy<PermissionStatement, string>> {
|
|
15
|
+
readonly role: {
|
|
16
|
+
assign(userId: string, role: PolicyRole<TPolicy>): Promise<void>;
|
|
17
|
+
revoke(userId: string, role: PolicyRole<TPolicy>): Promise<void>;
|
|
18
|
+
};
|
|
19
|
+
readonly permission: {
|
|
20
|
+
allow(userId: string, permission: PolicyPermission<TPolicy>): Promise<void>;
|
|
21
|
+
deny(userId: string, permission: PolicyPermission<TPolicy>): Promise<void>;
|
|
22
|
+
revoke(userId: string, permission: PolicyPermission<TPolicy>): Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
private readonly policy;
|
|
25
|
+
private readonly repository;
|
|
26
|
+
constructor({ policy, repository, }: {
|
|
27
|
+
policy: TPolicy;
|
|
28
|
+
repository: AuthorizationRepository;
|
|
29
|
+
});
|
|
30
|
+
resolve(userId: string): Promise<EffectivePermissions<PermissionOf<PolicyStatement<TPolicy>>>>;
|
|
31
|
+
can(userId: string, requirement: PermissionRequirement<PolicyStatement<TPolicy>>): Promise<boolean>;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppsScriptAuthorization = void 0;
|
|
4
|
+
class AppsScriptAuthorization {
|
|
5
|
+
role;
|
|
6
|
+
permission;
|
|
7
|
+
policy;
|
|
8
|
+
repository;
|
|
9
|
+
constructor({ policy, repository, }) {
|
|
10
|
+
this.policy = policy;
|
|
11
|
+
this.repository = repository;
|
|
12
|
+
this.role = {
|
|
13
|
+
assign: (userId, role) => this.repository.role.assign(userId, role),
|
|
14
|
+
revoke: (userId, role) => this.repository.role.revoke(userId, role),
|
|
15
|
+
};
|
|
16
|
+
this.permission = {
|
|
17
|
+
allow: (userId, permission) => this.repository.permission.set(userId, permission, "allow"),
|
|
18
|
+
deny: (userId, permission) => this.repository.permission.set(userId, permission, "deny"),
|
|
19
|
+
revoke: (userId, permission) => this.repository.permission.revoke(userId, permission),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async resolve(userId) {
|
|
23
|
+
const [roles, permissions] = await Promise.all([
|
|
24
|
+
this.repository.role.findByUserId(userId),
|
|
25
|
+
this.repository.permission.findByUserId(userId),
|
|
26
|
+
]);
|
|
27
|
+
return this.policy.resolve({
|
|
28
|
+
roles,
|
|
29
|
+
permissions,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async can(userId, requirement) {
|
|
33
|
+
return this.policy.can(await this.resolve(userId), requirement);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.AppsScriptAuthorization = AppsScriptAuthorization;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type PermissionStatement = Record<string, readonly string[]>;
|
|
2
|
+
export type PermissionOf<TStatement extends PermissionStatement> = {
|
|
3
|
+
[TResource in Extract<keyof TStatement, string>]: `${TResource}:${Extract<TStatement[TResource][number], string>}`;
|
|
4
|
+
}[Extract<keyof TStatement, string>];
|
|
5
|
+
export type PermissionRequirement<TStatement extends PermissionStatement> = {
|
|
6
|
+
readonly [TResource in keyof TStatement]?: readonly TStatement[TResource][number][];
|
|
7
|
+
};
|
|
8
|
+
export type EffectivePermissions<TPermission extends string> = readonly TPermission[];
|
|
9
|
+
export type PermissionEffect = "allow" | "deny";
|
|
10
|
+
export type StoredPermissionOverride = {
|
|
11
|
+
readonly permission: string;
|
|
12
|
+
readonly effect: PermissionEffect;
|
|
13
|
+
};
|
|
14
|
+
export type AuthorizationResolutionInput = {
|
|
15
|
+
readonly roles: readonly string[];
|
|
16
|
+
readonly permissions: readonly StoredPermissionOverride[];
|
|
17
|
+
};
|
|
18
|
+
type RoleGrantMap = ReadonlyMap<string, readonly string[]>;
|
|
19
|
+
export declare class AuthorizationPolicy<const TStatement extends PermissionStatement, TRole extends string = never> {
|
|
20
|
+
readonly statement: TStatement;
|
|
21
|
+
readonly $types: {
|
|
22
|
+
readonly role: TRole;
|
|
23
|
+
readonly permission: PermissionOf<TStatement>;
|
|
24
|
+
};
|
|
25
|
+
private readonly permissions;
|
|
26
|
+
private readonly roleGrants;
|
|
27
|
+
constructor(statement: TStatement, roleGrants?: RoleGrantMap);
|
|
28
|
+
linkRole<const TName extends string, const TRequirement extends PermissionRequirement<TStatement>>(name: TName, requirement: TRequirement): AuthorizationPolicy<TStatement, TRole | TName>;
|
|
29
|
+
resolve(input: AuthorizationResolutionInput): EffectivePermissions<PermissionOf<TStatement>>;
|
|
30
|
+
can(permissions: EffectivePermissions<PermissionOf<TStatement>>, requirement: PermissionRequirement<TStatement>): boolean;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthorizationPolicy = void 0;
|
|
4
|
+
function flattenRequirement(requirement) {
|
|
5
|
+
const permissions = [];
|
|
6
|
+
for (const [resource, actions] of Object.entries(requirement)) {
|
|
7
|
+
for (const action of actions ?? []) {
|
|
8
|
+
permissions.push(`${resource}:${action}`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return permissions;
|
|
12
|
+
}
|
|
13
|
+
function unique(values) {
|
|
14
|
+
return [...new Set(values)];
|
|
15
|
+
}
|
|
16
|
+
class AuthorizationPolicy {
|
|
17
|
+
statement;
|
|
18
|
+
$types;
|
|
19
|
+
permissions;
|
|
20
|
+
roleGrants;
|
|
21
|
+
constructor(statement, roleGrants = new Map()) {
|
|
22
|
+
this.statement = statement;
|
|
23
|
+
this.permissions = new Set(flattenRequirement(statement));
|
|
24
|
+
this.roleGrants = roleGrants;
|
|
25
|
+
}
|
|
26
|
+
linkRole(name, requirement) {
|
|
27
|
+
return new AuthorizationPolicy(this.statement, new Map([
|
|
28
|
+
...this.roleGrants,
|
|
29
|
+
[name, unique(flattenRequirement(requirement))],
|
|
30
|
+
]));
|
|
31
|
+
}
|
|
32
|
+
resolve(input) {
|
|
33
|
+
const deniedPermissions = new Set(input.permissions
|
|
34
|
+
.filter(({ effect }) => effect === "deny")
|
|
35
|
+
.map(({ permission }) => permission)
|
|
36
|
+
.filter((permission) => this.permissions.has(permission)));
|
|
37
|
+
const resolved = new Set();
|
|
38
|
+
for (const { effect, permission } of input.permissions) {
|
|
39
|
+
if (effect === "allow" &&
|
|
40
|
+
this.permissions.has(permission) &&
|
|
41
|
+
!deniedPermissions.has(permission)) {
|
|
42
|
+
resolved.add(permission);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const role of input.roles) {
|
|
46
|
+
const permissions = this.roleGrants.get(role);
|
|
47
|
+
if (permissions === undefined) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
for (const permission of permissions) {
|
|
51
|
+
if (!deniedPermissions.has(permission)) {
|
|
52
|
+
resolved.add(permission);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [...resolved];
|
|
57
|
+
}
|
|
58
|
+
can(permissions, requirement) {
|
|
59
|
+
const granted = new Set(permissions);
|
|
60
|
+
return flattenRequirement(requirement).every((permission) => granted.has(permission));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.AuthorizationPolicy = AuthorizationPolicy;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StoredPermissionOverride } from "./AuthorizationPolicy";
|
|
2
|
+
export interface AuthorizationRepository {
|
|
3
|
+
readonly role: {
|
|
4
|
+
findByUserId(userId: string): Promise<readonly string[]>;
|
|
5
|
+
assign(userId: string, role: string): Promise<void>;
|
|
6
|
+
revoke(userId: string, role: string): Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
readonly permission: {
|
|
9
|
+
findByUserId(userId: string): Promise<readonly StoredPermissionOverride[]>;
|
|
10
|
+
set(userId: string, permission: string, effect: StoredPermissionOverride["effect"]): Promise<void>;
|
|
11
|
+
revoke(userId: string, permission: string): Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AuthorizationPolicy, type AuthorizationResolutionInput, type EffectivePermissions, type PermissionEffect, type PermissionOf, type PermissionRequirement, type PermissionStatement, type StoredPermissionOverride, } from "./AuthorizationPolicy";
|