@ambushsoftworks/nestjs-auth-graphql 0.17.1 → 0.19.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 +99 -0
- package/README.md +363 -1
- package/dist/auth.module.d.ts +16 -0
- package/dist/auth.module.d.ts.map +1 -1
- package/dist/auth.module.js +71 -3
- package/dist/auth.module.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/decorators/allow-guest-session.decorator.d.ts +3 -0
- package/dist/decorators/allow-guest-session.decorator.d.ts.map +1 -0
- package/dist/decorators/allow-guest-session.decorator.js +8 -0
- package/dist/decorators/allow-guest-session.decorator.js.map +1 -0
- package/dist/decorators/current-guest.decorator.d.ts +2 -0
- package/dist/decorators/current-guest.decorator.d.ts.map +1 -0
- package/dist/decorators/current-guest.decorator.js +7 -0
- package/dist/decorators/current-guest.decorator.js.map +1 -0
- package/dist/exceptions/email-challenge.exceptions.d.ts +8 -0
- package/dist/exceptions/email-challenge.exceptions.d.ts.map +1 -0
- package/dist/exceptions/email-challenge.exceptions.js +21 -0
- package/dist/exceptions/email-challenge.exceptions.js.map +1 -0
- package/dist/exceptions/guest-session.exceptions.d.ts +9 -0
- package/dist/exceptions/guest-session.exceptions.d.ts.map +1 -0
- package/dist/exceptions/guest-session.exceptions.js +20 -0
- package/dist/exceptions/guest-session.exceptions.js.map +1 -0
- package/dist/guards/create-auth-guard.d.ts.map +1 -1
- package/dist/guards/create-auth-guard.js +29 -1
- package/dist/guards/create-auth-guard.js.map +1 -1
- package/dist/guards/guest-session.guard.d.ts +14 -0
- package/dist/guards/guest-session.guard.d.ts.map +1 -0
- package/dist/guards/guest-session.guard.js +63 -0
- package/dist/guards/guest-session.guard.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/auth-logger.interface.d.ts +10 -1
- package/dist/interfaces/auth-logger.interface.d.ts.map +1 -1
- package/dist/interfaces/auth-logger.interface.js +9 -0
- package/dist/interfaces/auth-logger.interface.js.map +1 -1
- package/dist/interfaces/email-challenge-repository.interface.d.ts +22 -0
- package/dist/interfaces/email-challenge-repository.interface.d.ts.map +1 -0
- package/dist/interfaces/email-challenge-repository.interface.js +3 -0
- package/dist/interfaces/email-challenge-repository.interface.js.map +1 -0
- package/dist/interfaces/email-service.interface.d.ts +5 -0
- package/dist/interfaces/email-service.interface.d.ts.map +1 -1
- package/dist/interfaces/email-template-renderer.interface.d.ts +7 -0
- package/dist/interfaces/email-template-renderer.interface.d.ts.map +1 -1
- package/dist/interfaces/guest-session-repository.interface.d.ts +37 -0
- package/dist/interfaces/guest-session-repository.interface.d.ts.map +1 -0
- package/dist/interfaces/guest-session-repository.interface.js +3 -0
- package/dist/interfaces/guest-session-repository.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +2 -0
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js +2 -0
- package/dist/interfaces/index.js.map +1 -1
- package/dist/repositories/in-memory-email-challenge.repository.d.ts +14 -0
- package/dist/repositories/in-memory-email-challenge.repository.d.ts.map +1 -0
- package/dist/repositories/in-memory-email-challenge.repository.js +55 -0
- package/dist/repositories/in-memory-email-challenge.repository.js.map +1 -0
- package/dist/repositories/in-memory-guest-session.repository.d.ts +18 -0
- package/dist/repositories/in-memory-guest-session.repository.d.ts.map +1 -0
- package/dist/repositories/in-memory-guest-session.repository.js +83 -0
- package/dist/repositories/in-memory-guest-session.repository.js.map +1 -0
- package/dist/services/configurable-email.service.d.ts +2 -1
- package/dist/services/configurable-email.service.d.ts.map +1 -1
- package/dist/services/configurable-email.service.js +24 -0
- package/dist/services/configurable-email.service.js.map +1 -1
- package/dist/services/default-email-template-renderer.d.ts +7 -0
- package/dist/services/default-email-template-renderer.d.ts.map +1 -1
- package/dist/services/default-email-template-renderer.js +31 -0
- package/dist/services/default-email-template-renderer.js.map +1 -1
- package/dist/services/email-challenge.service.d.ts +74 -0
- package/dist/services/email-challenge.service.d.ts.map +1 -0
- package/dist/services/email-challenge.service.js +306 -0
- package/dist/services/email-challenge.service.js.map +1 -0
- package/dist/services/guest-session.service.d.ts +80 -0
- package/dist/services/guest-session.service.d.ts.map +1 -0
- package/dist/services/guest-session.service.js +293 -0
- package/dist/services/guest-session.service.js.map +1 -0
- package/dist/services/passkey.service.d.ts.map +1 -1
- package/dist/services/passkey.service.js +8 -20
- package/dist/services/passkey.service.js.map +1 -1
- package/dist/testing/email-challenge-repository.contract.d.ts +15 -0
- package/dist/testing/email-challenge-repository.contract.d.ts.map +1 -0
- package/dist/testing/email-challenge-repository.contract.js +287 -0
- package/dist/testing/email-challenge-repository.contract.js.map +1 -0
- package/dist/testing/guest-session-repository.contract.d.ts +18 -0
- package/dist/testing/guest-session-repository.contract.d.ts.map +1 -0
- package/dist/testing/guest-session-repository.contract.js +368 -0
- package/dist/testing/guest-session-repository.contract.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +7 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/utils/rate-limit-helpers.d.ts +4 -0
- package/dist/utils/rate-limit-helpers.d.ts.map +1 -0
- package/dist/utils/rate-limit-helpers.js +20 -0
- package/dist/utils/rate-limit-helpers.js.map +1 -0
- package/examples/email-challenge/prisma-email-challenge.repository.ts +85 -0
- package/examples/email-challenge/schema.prisma +24 -0
- package/examples/guest-sessions/prisma-guest-session.repository.ts +86 -0
- package/examples/guest-sessions/schema.prisma +33 -0
- package/package.json +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { PrismaClient } from '@prisma/client';
|
|
3
|
+
import {
|
|
4
|
+
GuestGrantRecord,
|
|
5
|
+
GuestSessionRecord,
|
|
6
|
+
GuestSessionWithGrants,
|
|
7
|
+
IGuestSessionRepository,
|
|
8
|
+
} from '@ambushsoftworks/nestjs-auth-graphql';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* IGuestSessionRepository on Prisma, for the models in ./schema.prisma.
|
|
12
|
+
*
|
|
13
|
+
* Verified against PostgreSQL 16 with `assertGuestSessionRepositoryContract`
|
|
14
|
+
* from `@ambushsoftworks/nestjs-auth-graphql/testing`, with and without
|
|
15
|
+
* realms. Run that contract against your copy, too, on your real database:
|
|
16
|
+
*
|
|
17
|
+
* await assertGuestSessionRepositoryContract(() => new PrismaGuestSessionRepository(prisma), {
|
|
18
|
+
* cleanup: async ({ sessionIds, grantIds }) => {
|
|
19
|
+
* await prisma.guestGrant.deleteMany({ where: { id: { in: grantIds } } });
|
|
20
|
+
* await prisma.guestSession.deleteMany({ where: { id: { in: sessionIds } } });
|
|
21
|
+
* },
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* Inject your own PrismaService in place of PrismaClient if you have one.
|
|
25
|
+
*/
|
|
26
|
+
@Injectable()
|
|
27
|
+
export class PrismaGuestSessionRepository implements IGuestSessionRepository {
|
|
28
|
+
constructor(private readonly prisma: PrismaClient) {}
|
|
29
|
+
|
|
30
|
+
async createSession(session: GuestSessionRecord, grant: GuestGrantRecord): Promise<void> {
|
|
31
|
+
const { sessionId: _sessionId, ...firstGrant } = grant;
|
|
32
|
+
await this.prisma.guestSession.create({
|
|
33
|
+
data: { ...session, grants: { create: firstGrant } },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Every grant, whatever its state: the package decides what revoked and expired mean. */
|
|
38
|
+
async findSessionByTokenHash(tokenHash: string): Promise<GuestSessionWithGrants | null> {
|
|
39
|
+
return this.prisma.guestSession.findUnique({ where: { tokenHash }, include: { grants: true } });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async addGrant(grant: GuestGrantRecord): Promise<void> {
|
|
43
|
+
await this.prisma.guestGrant.create({ data: grant });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** One conditional update: never a read followed by a write. */
|
|
47
|
+
async rotateToken(sessionId: string, oldHash: string, newHash: string): Promise<boolean> {
|
|
48
|
+
const { count } = await this.prisma.guestSession.updateMany({
|
|
49
|
+
where: { id: sessionId, tokenHash: oldHash, revokedAt: null },
|
|
50
|
+
data: { tokenHash: newHash },
|
|
51
|
+
});
|
|
52
|
+
return count === 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async revokeSession(sessionId: string): Promise<boolean> {
|
|
56
|
+
const { count } = await this.prisma.guestSession.updateMany({
|
|
57
|
+
where: { id: sessionId, revokedAt: null },
|
|
58
|
+
data: { revokedAt: new Date() },
|
|
59
|
+
});
|
|
60
|
+
return count === 1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async revokeGrant(grantRecordId: string): Promise<boolean> {
|
|
64
|
+
const { count } = await this.prisma.guestGrant.updateMany({
|
|
65
|
+
where: { id: grantRecordId, revokedAt: null },
|
|
66
|
+
data: { revokedAt: new Date() },
|
|
67
|
+
});
|
|
68
|
+
return count === 1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async revokeGrants(filter: { kind: string; grantId: string; realm: string | null }): Promise<number> {
|
|
72
|
+
const { count } = await this.prisma.guestGrant.updateMany({
|
|
73
|
+
// `realm` goes through as given. null means "no realm" here; turning it
|
|
74
|
+
// into undefined would drop the condition and match every realm.
|
|
75
|
+
where: { kind: filter.kind, grantId: filter.grantId, realm: filter.realm, revokedAt: null },
|
|
76
|
+
data: { revokedAt: new Date() },
|
|
77
|
+
});
|
|
78
|
+
return count;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async deleteExpired(): Promise<number> {
|
|
82
|
+
const grants = await this.prisma.guestGrant.deleteMany({ where: { expiresAt: { lt: new Date() } } });
|
|
83
|
+
const sessions = await this.prisma.guestSession.deleteMany({ where: { grants: { none: {} } } });
|
|
84
|
+
return grants.count + sessions.count;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Reference schema for IGuestSessionRepository, as in the README ("Guest
|
|
2
|
+
// Sessions"). Verified against PostgreSQL 16 with
|
|
3
|
+
// `assertGuestSessionRepositoryContract`, with and without realms.
|
|
4
|
+
//
|
|
5
|
+
// Merge these two models into your schema. Neither relates to your User model,
|
|
6
|
+
// on purpose: a guest is not a user.
|
|
7
|
+
|
|
8
|
+
model GuestSession {
|
|
9
|
+
id String @id // generated by the package
|
|
10
|
+
tokenHash String @unique // looked up on every guest request
|
|
11
|
+
principalId String // your own id for the person
|
|
12
|
+
email String
|
|
13
|
+
realm String? // set when realms are enabled
|
|
14
|
+
revokedAt DateTime?
|
|
15
|
+
createdAt DateTime
|
|
16
|
+
grants GuestGrant[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
model GuestGrant {
|
|
20
|
+
id String @id // generated by the package
|
|
21
|
+
sessionId String
|
|
22
|
+
kind String // what routes opt in by: 'translation-job'
|
|
23
|
+
grantId String // your id for the thing granted
|
|
24
|
+
realm String? // copied from the session
|
|
25
|
+
expiresAt DateTime
|
|
26
|
+
revokedAt DateTime?
|
|
27
|
+
createdAt DateTime
|
|
28
|
+
session GuestSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
|
29
|
+
|
|
30
|
+
@@index([sessionId])
|
|
31
|
+
@@index([kind, grantId])
|
|
32
|
+
@@index([expiresAt])
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ambushsoftworks/nestjs-auth-graphql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|