@voltro/plugin-auth-social 0.86.0 → 0.88.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/CHANGELOG.md +5484 -0
- package/README.md +8 -1
- package/THIRD-PARTY-NOTICES.md +3 -227
- package/dist/apple.js +1 -2
- package/dist/callback.js +91 -76
- package/dist/discord.js +37 -0
- package/dist/epic.js +38 -0
- package/dist/errors.js +7 -4
- package/dist/github.js +10 -8
- package/dist/guestHandoff.js +60 -0
- package/dist/guestUpgrade.js +96 -0
- package/dist/identityStore.js +87 -68
- package/dist/index.d.ts +292 -16
- package/dist/index.js +16 -11
- package/dist/linking.js +2 -6
- package/dist/login.js +7 -3
- package/dist/nativeGuestUpgrade.js +65 -0
- package/dist/pkce.js +1 -2
- package/dist/platform.js +114 -0
- package/dist/plugin.js +608 -112
- package/dist/providers.js +72 -13
- package/dist/signIn.js +25 -9
- package/dist/steam.js +151 -0
- package/dist/web/guestUpgradeClient.js +108 -0
- package/dist/web.d.ts +54 -0
- package/dist/web.js +1 -0
- package/package.json +12 -6
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SocialConfigError as e } from "./errors.js";
|
|
2
|
+
import { isSocialProviderId as t } from "./providers.js";
|
|
3
|
+
import { signAuthClaims as n, verifyAuthClaims as r } from "@voltro/plugin-auth";
|
|
4
|
+
// src/guestHandoff.ts
|
|
5
|
+
var i = (t, r) => {
|
|
6
|
+
let i = t.profile, a = n({
|
|
7
|
+
exp: t.exp,
|
|
8
|
+
audience: t.audience,
|
|
9
|
+
guest: t.guest,
|
|
10
|
+
profile: {
|
|
11
|
+
provider: i.provider,
|
|
12
|
+
providerAccountId: i.providerAccountId,
|
|
13
|
+
email: i.email,
|
|
14
|
+
emailVerified: i.emailVerified,
|
|
15
|
+
emailIsPrivateRelay: i.emailIsPrivateRelay,
|
|
16
|
+
firstName: i.firstName,
|
|
17
|
+
lastName: i.lastName,
|
|
18
|
+
nameIsFirstAuthorizationOnly: i.nameIsFirstAuthorizationOnly
|
|
19
|
+
}
|
|
20
|
+
}, r.current.secret, "social-upgrade");
|
|
21
|
+
if (a.length > 3400) throw new e("Guest upgrade handoff exceeds its cookie budget");
|
|
22
|
+
return a;
|
|
23
|
+
}, a = (e) => typeof e == "object" && e && !Array.isArray(e) ? e : null, o = (e) => {
|
|
24
|
+
let t = a(e), n = a(t?.metadata);
|
|
25
|
+
return t?.type !== "user" || t.kind !== "guest" || typeof t.id != "string" || !/^guest_[A-Za-z0-9_-]+$/.test(t.id) || typeof t.tenantId != "string" || !t.tenantId.trim() || typeof n?.sessionId != "string" || !n.sessionId || typeof n.guestDeviceId != "string" || !/^gdev_[A-Za-z0-9_-]+$/.test(n.guestDeviceId) || typeof n.guestDeviceGeneration != "number" || !Number.isSafeInteger(n.guestDeviceGeneration) || n.guestDeviceGeneration < 0 ? null : {
|
|
26
|
+
type: "user",
|
|
27
|
+
kind: "guest",
|
|
28
|
+
id: t.id,
|
|
29
|
+
tenantId: t.tenantId,
|
|
30
|
+
metadata: {
|
|
31
|
+
sessionId: n.sessionId,
|
|
32
|
+
guestDeviceId: n.guestDeviceId,
|
|
33
|
+
guestDeviceGeneration: n.guestDeviceGeneration
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}, s = (e, n, i) => {
|
|
37
|
+
if (!e || e.length > 3400) return null;
|
|
38
|
+
let s = [n.current, n.previous].filter((e) => e !== void 0).map((t) => r(e, t.secret, "social-upgrade")).find((e) => e !== null);
|
|
39
|
+
if (!s || s.audience !== i || typeof s.exp != "number") return null;
|
|
40
|
+
let c = o(s.guest), l = a(s.profile), u = (e) => e === null || typeof e == "string";
|
|
41
|
+
return !c || !l || typeof l.provider != "string" || !t(l.provider) || typeof l.providerAccountId != "string" || !l.providerAccountId || !u(l.email) || !u(l.firstName) || !u(l.lastName) || typeof l.emailVerified != "boolean" || typeof l.emailIsPrivateRelay != "boolean" || typeof l.nameIsFirstAuthorizationOnly != "boolean" ? null : {
|
|
42
|
+
guest: c,
|
|
43
|
+
exp: s.exp,
|
|
44
|
+
audience: i,
|
|
45
|
+
profile: {
|
|
46
|
+
provider: l.provider,
|
|
47
|
+
providerAccountId: l.providerAccountId,
|
|
48
|
+
email: l.email,
|
|
49
|
+
emailVerified: l.emailVerified,
|
|
50
|
+
emailIsPrivateRelay: l.emailIsPrivateRelay,
|
|
51
|
+
firstName: l.firstName,
|
|
52
|
+
lastName: l.lastName,
|
|
53
|
+
nameIsFirstAuthorizationOnly: l.nameIsFirstAuthorizationOnly,
|
|
54
|
+
name: null,
|
|
55
|
+
avatarUrl: null,
|
|
56
|
+
raw: {}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
export { s as decodeGuestUpgradeHandoff, i as encodeGuestUpgradeHandoff, o as guestIdentityOf };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { SOCIAL_IDENTITY_TABLE as e, dataStoreSocialIdentityStore as t } from "./identityStore.js";
|
|
2
|
+
import { Effect as n } from "effect";
|
|
3
|
+
import { and as r, eq as i } from "@voltro/database";
|
|
4
|
+
import { GuestAuthError as a, dataStoreGuestAuth as o, dataStoreSessionRegistry as s, issueUserSession as c, runSubjectGuards as l } from "@voltro/plugin-auth";
|
|
5
|
+
// src/guestUpgrade.ts
|
|
6
|
+
var u = (e, t, n) => ({
|
|
7
|
+
table: e,
|
|
8
|
+
predicate: i(t, n),
|
|
9
|
+
order: [],
|
|
10
|
+
take: void 0,
|
|
11
|
+
skip: void 0,
|
|
12
|
+
projection: void 0
|
|
13
|
+
}), d = (d) => {
|
|
14
|
+
if (d.config.defaultTenantId !== d.guest.tenantId || d.config.ensureActor !== void 0 && d.configForTransaction === void 0) return n.succeed({
|
|
15
|
+
kind: "refused",
|
|
16
|
+
status: 500,
|
|
17
|
+
code: "config",
|
|
18
|
+
message: "Guest upgrade requires a matching tenant and transaction-bound actor hooks."
|
|
19
|
+
});
|
|
20
|
+
let f = d.profile, p = f.email === null || f.email.length === 0 ? null : f.email;
|
|
21
|
+
return (d.service ?? o(d.store, d.guest)).upgrade(d.credential, async (o) => {
|
|
22
|
+
let m = o.store, h = t(m);
|
|
23
|
+
if (await n.runPromise(h.findByProviderAccount(f.provider, f.providerAccountId)) !== null || p !== null && (await m.query(u("users", "email", p))).length !== 0) throw new a({ code: "upgrade_conflict" });
|
|
24
|
+
let g = {
|
|
25
|
+
id: o.subjectId,
|
|
26
|
+
tenantId: o.tenantId,
|
|
27
|
+
email: p,
|
|
28
|
+
passwordHash: null,
|
|
29
|
+
createdAt: o.createdAt,
|
|
30
|
+
mfaSecret: null,
|
|
31
|
+
mfaEnrolledAt: null,
|
|
32
|
+
emailVerifiedAt: p !== null && f.emailVerified ? /* @__PURE__ */ new Date() : null
|
|
33
|
+
}, _ = d.configForTransaction?.(m) ?? d.config;
|
|
34
|
+
if (_.defaultTenantId !== o.tenantId || !(await n.runPromise(l(_.subjectGuards ?? [], g))).ok) throw new a({ code: "credential_rejected" });
|
|
35
|
+
if (await m.insert("users", {
|
|
36
|
+
...g,
|
|
37
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
38
|
+
}), !await n.runPromise(h.insert({
|
|
39
|
+
userId: g.id,
|
|
40
|
+
provider: f.provider,
|
|
41
|
+
providerAccountId: f.providerAccountId,
|
|
42
|
+
email: p,
|
|
43
|
+
emailVerified: p !== null && f.emailVerified
|
|
44
|
+
}).pipe(n.as(!0), n.catchTag("SocialIdentityConflict", () => n.succeed(!1))))) throw new a({ code: "upgrade_conflict" });
|
|
45
|
+
let v = {
|
|
46
|
+
...d.users,
|
|
47
|
+
...s(m),
|
|
48
|
+
listMemberships: (e) => n.promise(async () => (await m.query({
|
|
49
|
+
...u("memberships", "userId", e),
|
|
50
|
+
predicate: r(i("userId", e), i("tenantId", o.tenantId))
|
|
51
|
+
})).map((t) => {
|
|
52
|
+
if (t.userId !== e || t.tenantId !== o.tenantId || typeof t.role != "string") throw new a({ code: "store_unavailable" });
|
|
53
|
+
let n = t.joinedAt instanceof Date ? t.joinedAt : new Date(String(t.joinedAt));
|
|
54
|
+
if (!Number.isFinite(n.getTime())) throw new a({ code: "store_unavailable" });
|
|
55
|
+
return {
|
|
56
|
+
userId: e,
|
|
57
|
+
tenantId: o.tenantId,
|
|
58
|
+
role: t.role,
|
|
59
|
+
joinedAt: n
|
|
60
|
+
};
|
|
61
|
+
}))
|
|
62
|
+
}, y = await n.runPromise(c(g, v, _, {
|
|
63
|
+
clearLoginFailures: !1,
|
|
64
|
+
ipAddress: d.ipAddress ?? null,
|
|
65
|
+
userAgent: d.userAgent ?? null
|
|
66
|
+
})), b = y.subject.type === "user" ? y.subject.metadata?.sessionId : null;
|
|
67
|
+
if (typeof b != "string" || (await m.query(u("sessions", "id", b))).length !== 1) throw new a({ code: "store_unavailable" });
|
|
68
|
+
let x = (await m.query({
|
|
69
|
+
...u(e, "provider", f.provider),
|
|
70
|
+
predicate: r(i("provider", f.provider), i("providerAccountId", f.providerAccountId))
|
|
71
|
+
}))[0];
|
|
72
|
+
if (!x || x.provider !== f.provider || x.providerAccountId !== f.providerAccountId || x.userId !== g.id) throw new a({ code: "upgrade_conflict" });
|
|
73
|
+
return {
|
|
74
|
+
kind: "ok",
|
|
75
|
+
userId: g.id,
|
|
76
|
+
subject: y.subject,
|
|
77
|
+
setCookie: y.setCookie,
|
|
78
|
+
session: {
|
|
79
|
+
value: y.value,
|
|
80
|
+
expiresAt: y.expiresAt
|
|
81
|
+
},
|
|
82
|
+
created: !0,
|
|
83
|
+
linked: !0,
|
|
84
|
+
oneTimeName: f.nameIsFirstAuthorizationOnly ? {
|
|
85
|
+
firstName: f.firstName,
|
|
86
|
+
lastName: f.lastName
|
|
87
|
+
} : null
|
|
88
|
+
};
|
|
89
|
+
}).pipe(n.catch((e) => n.succeed({
|
|
90
|
+
kind: "refused",
|
|
91
|
+
status: e.code === "upgrade_conflict" ? 409 : e.code === "credential_rejected" ? 403 : 503,
|
|
92
|
+
code: e.code === "upgrade_conflict" ? "account_merge_required" : e.code,
|
|
93
|
+
message: e.code === "upgrade_conflict" ? "The provider or email belongs to an existing account. Confirm both accounts before merging." : e.code === "credential_rejected" ? "Guest upgrade was refused." : "Guest upgrade storage is unavailable."
|
|
94
|
+
})));
|
|
95
|
+
};
|
|
96
|
+
export { d as completeGuestSocialUpgrade };
|
package/dist/identityStore.js
CHANGED
|
@@ -1,104 +1,123 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { and as
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
id:
|
|
6
|
-
userId:
|
|
7
|
-
provider:
|
|
8
|
-
providerAccountId:
|
|
9
|
-
email:
|
|
10
|
-
emailVerified:
|
|
11
|
-
createdAt:
|
|
12
|
-
lastLoginAt:
|
|
13
|
-
}).unique("byOauthProviderAccount", ["provider", "providerAccountId"]).index(["userId"]),
|
|
1
|
+
import { Data as e, Effect as t } from "effect";
|
|
2
|
+
import { and as n, boolean as r, classifyConstraintViolation as i, eq as a, extractDbCause as o, generateId as s, id as c, table as l, text as u, timestamp as d } from "@voltro/database";
|
|
3
|
+
// src/identityStore.ts
|
|
4
|
+
var f = "_voltro_oauth_identities", p = l(f, {
|
|
5
|
+
id: c({ prefix: "oauthid" }),
|
|
6
|
+
userId: u(),
|
|
7
|
+
provider: u(),
|
|
8
|
+
providerAccountId: u(),
|
|
9
|
+
email: u().nullable(),
|
|
10
|
+
emailVerified: r().default(!1),
|
|
11
|
+
createdAt: d().default("now"),
|
|
12
|
+
lastLoginAt: d().nullable()
|
|
13
|
+
}).unique("byOauthProviderAccount", ["provider", "providerAccountId"]).index(["userId"]), m = [p], h = class extends e.TaggedError("SocialIdentityConflict") {}, g = (e) => typeof e == "object" && !!e && e._tag === "ConstraintViolation" && e.kind === "unique" || i(o(e), "insert")?.kind === "unique", _ = () => s({
|
|
14
14
|
kind: "typeid",
|
|
15
15
|
prefix: "oauthid"
|
|
16
|
-
}, "oauthid"),
|
|
17
|
-
let n = [...
|
|
16
|
+
}, "oauthid"), v = (e = []) => {
|
|
17
|
+
let n = [...e];
|
|
18
18
|
return {
|
|
19
|
-
findByProviderAccount: (
|
|
20
|
-
listForUser: (
|
|
21
|
-
insert: (t) => e.sync(() => {
|
|
22
|
-
let
|
|
23
|
-
...
|
|
24
|
-
id:
|
|
19
|
+
findByProviderAccount: (e, r) => t.sync(() => n.find((t) => t.provider === e && t.providerAccountId === r) ?? null),
|
|
20
|
+
listForUser: (e) => t.sync(() => n.filter((t) => t.userId === e)),
|
|
21
|
+
insert: (e) => n.some((t) => t.provider === e.provider && t.providerAccountId === e.providerAccountId) ? t.fail(new h({ provider: e.provider })) : t.sync(() => {
|
|
22
|
+
let t = {
|
|
23
|
+
...e,
|
|
24
|
+
id: _(),
|
|
25
25
|
createdAt: /* @__PURE__ */ new Date(),
|
|
26
26
|
lastLoginAt: null
|
|
27
27
|
};
|
|
28
|
-
return n.push(
|
|
28
|
+
return n.push(t), t;
|
|
29
29
|
}),
|
|
30
|
-
touch: (
|
|
31
|
-
let
|
|
32
|
-
|
|
33
|
-
...n[
|
|
30
|
+
touch: (e, r) => t.sync(() => {
|
|
31
|
+
let t = n.findIndex((t) => t.id === e);
|
|
32
|
+
t >= 0 && (n[t] = {
|
|
33
|
+
...n[t],
|
|
34
34
|
lastLoginAt: r
|
|
35
35
|
});
|
|
36
36
|
}),
|
|
37
|
-
remove: (
|
|
38
|
-
let
|
|
39
|
-
return
|
|
37
|
+
remove: (e, r) => t.sync(() => {
|
|
38
|
+
let t = n.findIndex((t) => t.userId === e && t.provider === r);
|
|
39
|
+
return t < 0 ? !1 : (n.splice(t, 1), !0);
|
|
40
40
|
})
|
|
41
41
|
};
|
|
42
|
-
},
|
|
42
|
+
}, y = (e) => {
|
|
43
43
|
if (e instanceof Date) return e;
|
|
44
44
|
if (typeof e == "string" || typeof e == "number") {
|
|
45
45
|
let t = new Date(e);
|
|
46
46
|
return Number.isNaN(t.getTime()) ? null : t;
|
|
47
47
|
}
|
|
48
48
|
return null;
|
|
49
|
-
},
|
|
49
|
+
}, b = (e) => ({
|
|
50
50
|
id: String(e.id ?? ""),
|
|
51
51
|
userId: String(e.userId ?? ""),
|
|
52
52
|
provider: String(e.provider ?? ""),
|
|
53
53
|
providerAccountId: String(e.providerAccountId ?? ""),
|
|
54
54
|
email: typeof e.email == "string" && e.email.length > 0 ? e.email : null,
|
|
55
55
|
emailVerified: e.emailVerified === !0 || e.emailVerified === 1,
|
|
56
|
-
createdAt:
|
|
57
|
-
lastLoginAt:
|
|
58
|
-
}),
|
|
59
|
-
findByProviderAccount: (
|
|
60
|
-
let
|
|
61
|
-
table:
|
|
62
|
-
predicate:
|
|
63
|
-
limit: 1
|
|
56
|
+
createdAt: y(e.createdAt) ?? /* @__PURE__ */ new Date(0),
|
|
57
|
+
lastLoginAt: y(e.lastLoginAt)
|
|
58
|
+
}), x = (e) => ({
|
|
59
|
+
findByProviderAccount: (r, i) => t.promise(async () => {
|
|
60
|
+
let t = (await e.query({
|
|
61
|
+
table: f,
|
|
62
|
+
predicate: n(a("provider", r), a("providerAccountId", i)),
|
|
63
|
+
limit: 1,
|
|
64
|
+
take: 1,
|
|
65
|
+
skip: void 0,
|
|
66
|
+
projection: void 0,
|
|
67
|
+
order: []
|
|
64
68
|
}))[0];
|
|
65
|
-
return
|
|
69
|
+
return t ? b(t) : null;
|
|
66
70
|
}),
|
|
67
|
-
listForUser: (
|
|
68
|
-
table:
|
|
69
|
-
predicate:
|
|
71
|
+
listForUser: (n) => t.promise(async () => (await e.query({
|
|
72
|
+
table: f,
|
|
73
|
+
predicate: a("userId", n),
|
|
70
74
|
order: [{
|
|
71
75
|
column: "createdAt",
|
|
72
76
|
direction: "asc"
|
|
73
|
-
}]
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
77
|
+
}],
|
|
78
|
+
take: void 0,
|
|
79
|
+
skip: void 0,
|
|
80
|
+
projection: void 0
|
|
81
|
+
})).map(b)),
|
|
82
|
+
insert: (n) => t.tryPromise({
|
|
83
|
+
try: async () => {
|
|
84
|
+
let t = {
|
|
85
|
+
id: _(),
|
|
86
|
+
userId: n.userId,
|
|
87
|
+
provider: n.provider,
|
|
88
|
+
providerAccountId: n.providerAccountId,
|
|
89
|
+
email: n.email,
|
|
90
|
+
emailVerified: n.emailVerified,
|
|
91
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
92
|
+
lastLoginAt: null
|
|
93
|
+
};
|
|
94
|
+
if (!("insertIgnoreWithOutcome" in e) || e.insertIgnoreWithOutcome === void 0) return b(await e.insert(f, t));
|
|
95
|
+
let r = await e.insertIgnoreWithOutcome(f, t, { conflictColumns: ["provider", "providerAccountId"] });
|
|
96
|
+
if (r.outcome === "ignored") throw new h({ provider: n.provider });
|
|
97
|
+
return b(r.row);
|
|
98
|
+
},
|
|
99
|
+
catch: (e) => e
|
|
100
|
+
}).pipe(t.catch((e) => e instanceof h || g(e) ? t.fail(new h({ provider: n.provider })) : t.die(e))),
|
|
101
|
+
touch: (n, r) => t.promise(async () => {
|
|
102
|
+
await e.update(f, n, { lastLoginAt: r });
|
|
87
103
|
}),
|
|
88
|
-
remove: (
|
|
89
|
-
let
|
|
90
|
-
table:
|
|
91
|
-
predicate:
|
|
92
|
-
limit: 1
|
|
104
|
+
remove: (r, i) => t.promise(async () => {
|
|
105
|
+
let t = (await e.query({
|
|
106
|
+
table: f,
|
|
107
|
+
predicate: n(a("userId", r), a("provider", i)),
|
|
108
|
+
limit: 1,
|
|
109
|
+
take: 1,
|
|
110
|
+
skip: void 0,
|
|
111
|
+
projection: void 0,
|
|
112
|
+
order: []
|
|
93
113
|
}))[0];
|
|
94
|
-
return
|
|
114
|
+
return t ? e.delete(f, String(t.id ?? "")) : !1;
|
|
95
115
|
})
|
|
96
|
-
}),
|
|
97
|
-
let i = yield*
|
|
98
|
-
return i ? i.userId === n ? i : yield*
|
|
116
|
+
}), S = (e, n, r) => t.gen(function* () {
|
|
117
|
+
let i = yield* e.findByProviderAccount(r.provider, r.providerAccountId);
|
|
118
|
+
return i ? i.userId === n ? i : yield* t.fail(/* @__PURE__ */ Error(`linkSocialIdentity: this ${r.provider} account is already linked to another user`)) : yield* e.insert({
|
|
99
119
|
...r,
|
|
100
120
|
userId: n
|
|
101
121
|
});
|
|
102
122
|
});
|
|
103
|
-
|
|
104
|
-
export { l as SOCIAL_IDENTITY_TABLE, g as dataStoreSocialIdentityStore, _ as linkSocialIdentity, p as memorySocialIdentityStore, d as socialAuthTables, u as socialIdentitiesTable };
|
|
123
|
+
export { f as SOCIAL_IDENTITY_TABLE, h as SocialIdentityConflict, x as dataStoreSocialIdentityStore, S as linkSocialIdentity, v as memorySocialIdentityStore, m as socialAuthTables, p as socialIdentitiesTable };
|