ReviewOS

also looking at this

stacks/bench-review

Close unauthenticated /api/requests CRUD, and make the session cookie HttpOnly

#77
Merged glennmichael123 wants to merge fix/request-autocrud-and-httponly into main
11 files +552 -57
app/Actions/Auth/RegisterAction.tsadded+70-0
Changes to app/Actions/Auth/RegisterAction.ts
@@ -0,0 +1,70 @@
1import type { RequestInstance } from '@stacksjs/types'
2import { Action } from '@stacksjs/actions'
3import { Auth, register } from '@stacksjs/auth'
4import { dispatch } from '@stacksjs/events'
5import { response } from '@stacksjs/router'
6import { schema } from '@stacksjs/validation'
7import { withSessionCookie } from '../../Support/sessionCookie'
8
9/**
10 * Register — app-local override of the framework default, identical except that
11 * the new session arrives as an `HttpOnly` cookie rather than being written by
12 * the browser. See `app/Support/sessionCookie.ts`.
13 *
14 * Registration logs the user straight in, so it mints a session and therefore
15 * needs the same cookie treatment as login; without it a freshly registered
16 * user would be the one remaining path that persisted a script-readable token.
17 */
18export default new Action({
19 name: 'RegisterAction',
20 description: 'Register a new user',
21 method: 'POST',
22
23 validations: {
24 email: {
25 rule: schema.string().email(),
26 message: 'Email must be a valid email address.',
27 },
28 password: {
29 rule: schema.string().min(6).max(255),
30 message: 'Password must be between 6 and 255 characters.',
31 },
32 name: {
33 rule: schema.string().min(2).max(255),
34 message: 'Name must be between 2 and 255 characters.',
35 },
36 },
37
38 async handle(request: RequestInstance) {
39 const email = request.get('email')
40 const password = request.get('password')
41 const name = request.get('name')
42
43 const result = await register({ email, password, name })
44
45 if (result) {
46 const user = await Auth.getUserFromToken(result.token)
47
48 // Fire `user:registered` so app/Events.ts listeners (welcome email, CRM
49 // sync, etc.) run. Fire-and-forget — listener errors are caught by the
50 // wildcard handler so a flaky welcome email doesn't fail registration.
51 dispatch('user:registered', {
52 id: user?.id,
53 email: user?.email,
54 name: user?.name,
55 to: user?.email,
56 })
57
58 return withSessionCookie({
59 token: result.token,
60 user: {
61 id: user?.id,
62 email: user?.email,
63 name: user?.name,
64 },
65 }, result.token)
66 }
67
68 return response.error('Registration failed')
69 },
70})