Skip to content

Commit

Permalink
trpc: Add anonymous procedure
Browse files Browse the repository at this point in the history
  • Loading branch information
farnoux committed Nov 20, 2024
1 parent 01564b8 commit d210385
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 8 deletions.
22 changes: 20 additions & 2 deletions backend/src/auth/models/authenticated-user.models.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import { User } from '@supabase/supabase-js';
import { User as SupabaseUser } from '@supabase/supabase-js';

export enum UserRole {
AUTHENTICATED = 'authenticated',
SERVICE_ROLE = 'service_role',
ANON = 'anon', // Anonymous
}

export type User = SupabaseUser;

export interface AnonymousUser extends User {
role: UserRole.ANON;
is_anonymous: true;
}

export interface AuthenticatedUser extends User {
role: UserRole;
role: UserRole.AUTHENTICATED;
is_anonymous: false;
}

export function isAnonymousUser(user: User | null): user is AnonymousUser {
return user?.role === UserRole.ANON && user.is_anonymous === true;
}

export function isAuthenticatedUser(
user: User | null
): user is AuthenticatedUser {
return user?.role === UserRole.AUTHENTICATED && user.is_anonymous === false;
}
6 changes: 4 additions & 2 deletions backend/src/auth/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { and, eq, inArray, sql, SQL, SQLWrapper } from 'drizzle-orm';
import DatabaseService from '../../common/services/database.service';
import {
AuthenticatedUser,
isAuthenticatedUser,
User,
UserRole,
} from '../models/authenticated-user.models';
import {
Expand Down Expand Up @@ -163,7 +165,7 @@ export class AuthService {
* @param doNotThrow vrai pour ne pas générer une exception
*/
async verifieAccesRestreintCollectivite(
user: AuthenticatedUser,
user: User,
collectiviteId: number,
doNotThrow?: boolean
): Promise<boolean> {
Expand All @@ -172,7 +174,7 @@ export class AuthService {
`Rôle de service détecté, accès autorisé à toutes les collectivités`
);
return true;
} else if (user.role === UserRole.AUTHENTICATED) {
} else if (isAuthenticatedUser(user)) {
let authorise = false;
const collectivite = await this.collectiviteService.getCollectivite(
collectiviteId
Expand Down
26 changes: 23 additions & 3 deletions backend/src/trpc/trpc.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Injectable } from '@nestjs/common';
import { initTRPC, TRPCError } from '@trpc/server';
import {
isAnonymousUser,
isAuthenticatedUser,
} from '../auth/models/authenticated-user.models';
import { Context } from './trpc.router';
import { AuthenticatedUser } from '../auth/models/authenticated-user.models';

@Injectable()
export class TrpcService {
Expand All @@ -14,9 +17,26 @@ export class TrpcService {

publicProcedure = this.trpc.procedure;

anonProcedure = this.trpc.procedure.use(
this.trpc.middleware(({ next, ctx }) => {
const anonUser = ctx.user;

if (!isAnonymousUser(anonUser)) {
throw new TRPCError({
code: 'UNAUTHORIZED',
message: 'Not anonymous',
});
}

return next({ ctx: { user: anonUser } });
})
);

authedProcedure = this.trpc.procedure.use(
this.trpc.middleware(({ next, ctx }) => {
if (ctx.user === null) {
const authUser = ctx.user;

if (!isAuthenticatedUser(authUser)) {
throw new TRPCError({
code: 'UNAUTHORIZED',
message: 'Not authenticated',
Expand All @@ -25,7 +45,7 @@ export class TrpcService {

return next({
ctx: {
user: ctx.user as AuthenticatedUser,
user: authUser,
},
});
})
Expand Down
14 changes: 13 additions & 1 deletion doc/adr/0004-trpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,26 @@ countByStatut: this.trpc.publicProcedure.input(inputSchema).query(({ input }) =>
/* Dans le router */
countByStatut: this.trpc.authedProcedure.input(inputSchema).query(({ input, ctx }) => {
const { collectiviteId, body } = input;
return this.service.countByStatut(collectiviteId, body, ctx.user);
const authenticatedUser = ctx.user;
return this.service.countByStatut(collectiviteId, body, authenticatedUser);
});

/* Dans le service */
const uuid = user.id;
const role = user.role;
```

- `anonProcedure` pour les routes avec un token anonyme et récupération du user (anonyme) via le `ctx` de la query.

```typescript
/* Dans le router */
countByStatut: this.trpc.anonProcedure.input(inputSchema).query(({ input, ctx }) => {
const { collectiviteId, body } = input;
const anonymousUser = ctx.user;
return this.service.countByStatut(collectiviteId, body, anonymousUser);
});
```

## Améliorations possibles

- Mise en place d'outils facilitant la DX.
Expand Down

0 comments on commit d210385

Please sign in to comment.