odac 0.9.0 → 1.0.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/.github/workflows/auto-pr-description.yml +0 -2
- package/.github/workflows/codeql.yml +46 -0
- package/.github/workflows/release.yml +13 -6
- package/.github/workflows/test-coverage.yml +10 -9
- package/.releaserc.js +9 -6
- package/CHANGELOG.md +62 -150
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTING.md +8 -8
- package/LICENSE +21 -661
- package/README.md +12 -12
- package/SECURITY.md +4 -4
- package/bin/odac.js +101 -0
- package/{framework/web/candy.js → client/odac.js} +310 -44
- package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
- package/docs/backend/01-overview/03-development-server.md +11 -11
- package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +1 -1
- package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
- package/docs/backend/03-config/04-environment-variables.md +20 -20
- package/docs/backend/03-config/05-early-hints.md +4 -4
- package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
- package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
- package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
- package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
- package/docs/backend/04-routing/05-advanced-routing.md +3 -3
- package/docs/backend/04-routing/06-error-pages.md +17 -17
- package/docs/backend/04-routing/07-cron-jobs.md +13 -13
- package/docs/backend/04-routing/08-middleware.md +214 -0
- package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
- package/docs/backend/04-routing/09-websocket-examples.md +381 -0
- package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
- package/docs/backend/04-routing/09-websocket.md +298 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
- package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
- package/docs/backend/05-controllers/03-controller-classes.md +19 -19
- package/docs/backend/05-forms/01-custom-forms.md +114 -114
- package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
- package/docs/backend/07-views/01-the-view-directory.md +1 -1
- package/docs/backend/07-views/02-rendering-a-view.md +22 -22
- package/docs/backend/07-views/03-template-syntax.md +52 -52
- package/docs/backend/07-views/03-variables.md +84 -84
- package/docs/backend/07-views/04-request-data.md +57 -57
- package/docs/backend/07-views/05-conditionals.md +78 -78
- package/docs/backend/07-views/06-loops.md +114 -114
- package/docs/backend/07-views/07-translations.md +66 -66
- package/docs/backend/07-views/08-backend-javascript.md +103 -103
- package/docs/backend/07-views/09-comments.md +71 -71
- package/docs/backend/08-database/01-database-connection.md +8 -8
- package/docs/backend/08-database/02-using-mysql.md +49 -49
- package/docs/backend/09-validation/01-the-validator-service.md +38 -38
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
- package/docs/backend/10-authentication/03-register.md +12 -12
- package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
- package/docs/backend/10-authentication/05-session-management.md +10 -10
- package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
- package/docs/backend/11-mail/01-the-mail-service.md +5 -5
- package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
- package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
- package/docs/frontend/01-overview/01-introduction.md +30 -30
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
- package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
- package/docs/frontend/03-forms/01-form-handling.md +32 -32
- package/docs/frontend/04-api-requests/01-get-post.md +33 -33
- package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
- package/docs/frontend/06-websocket/00-overview.md +76 -0
- package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
- package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
- package/docs/index.json +49 -11
- package/eslint.config.mjs +6 -6
- package/{framework/index.js → index.js} +1 -1
- package/package.json +14 -39
- package/{framework/src → src}/Auth.js +59 -59
- package/{framework/src → src}/Config.js +3 -3
- package/{framework/src → src}/Lang.js +7 -7
- package/{framework/src → src}/Mail.js +5 -5
- package/{framework/src → src}/Mysql.js +42 -42
- package/src/Odac.js +112 -0
- package/{framework/src → src}/Request.js +38 -36
- package/{framework/src → src}/Route/Internal.js +116 -116
- package/src/Route/Middleware.js +75 -0
- package/src/Route.js +621 -0
- package/src/Server.js +22 -0
- package/{framework/src → src}/Stream.js +11 -3
- package/{framework/src → src}/Validator.js +21 -21
- package/{framework/src → src}/Var.js +5 -5
- package/{framework/src → src}/View/EarlyHints.js +1 -1
- package/{framework/src → src}/View/Form.js +69 -69
- package/{framework/src → src}/View.js +78 -81
- package/src/WebSocket.js +403 -0
- package/template/config.json +5 -0
- package/{web → template}/controller/page/about.js +6 -6
- package/{web → template}/controller/page/index.js +9 -9
- package/{web → template}/package.json +4 -5
- package/{web → template}/public/assets/css/style.css +4 -4
- package/{web → template}/public/assets/js/app.js +6 -6
- package/{web → template}/route/www.js +6 -6
- package/{web → template}/skeleton/main.html +1 -1
- package/{web → template}/view/content/about.html +5 -5
- package/{web → template}/view/content/home.html +12 -12
- package/template/view/footer/main.html +11 -0
- package/{web → template}/view/head/main.html +1 -1
- package/{web → template}/view/header/main.html +2 -2
- package/test/core/Candy.test.js +58 -58
- package/test/core/Commands.test.js +7 -7
- package/test/core/Config.test.js +82 -85
- package/test/core/Lang.test.js +2 -2
- package/test/core/Process.test.js +6 -6
- package/test/framework/Route.test.js +56 -37
- package/test/framework/View/EarlyHints.test.js +2 -2
- package/test/framework/WebSocket.test.js +100 -0
- package/test/framework/middleware.test.js +85 -0
- package/test/server/Api.test.js +31 -31
- package/test/server/DNS.test.js +11 -11
- package/test/server/Hub.test.js +497 -0
- package/test/server/Mail.account.test_.js +3 -3
- package/test/server/Mail.init.test_.js +10 -10
- package/test/server/Mail.test_.js +20 -20
- package/test/server/SSL.test_.js +54 -54
- package/test/server/Server.test.js +39 -39
- package/test/server/Service.test_.js +7 -7
- package/test/server/Subdomain.test.js +7 -7
- package/test/server/Web/Firewall.test.js +87 -87
- package/test/server/Web/Proxy.test.js +397 -0
- package/test/server/{Web.test_.js → Web.test.js} +137 -205
- package/test/server/__mocks__/fs.js +2 -2
- package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
- package/test/server/__mocks__/index.js +6 -6
- package/test/server/__mocks__/testFactories.js +1 -1
- package/test/server/__mocks__/testHelpers.js +7 -7
- package/.husky/pre-commit +0 -2
- package/.kiro/steering/code-style.md +0 -56
- package/.kiro/steering/product.md +0 -20
- package/.kiro/steering/structure.md +0 -77
- package/.kiro/steering/tech.md +0 -87
- package/AGENTS.md +0 -84
- package/bin/candy +0 -10
- package/bin/candypack +0 -10
- package/cli/index.js +0 -3
- package/cli/src/Cli.js +0 -348
- package/cli/src/Connector.js +0 -93
- package/cli/src/Monitor.js +0 -416
- package/core/Candy.js +0 -87
- package/core/Commands.js +0 -239
- package/core/Config.js +0 -1094
- package/core/Lang.js +0 -52
- package/core/Log.js +0 -43
- package/core/Process.js +0 -26
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
- package/docs/server/01-installation/01-quick-install.md +0 -19
- package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
- package/docs/server/02-get-started/01-core-concepts.md +0 -7
- package/docs/server/02-get-started/02-basic-commands.md +0 -57
- package/docs/server/02-get-started/03-cli-reference.md +0 -276
- package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
- package/docs/server/03-service/01-start-a-new-service.md +0 -57
- package/docs/server/03-service/02-delete-a-service.md +0 -48
- package/docs/server/04-web/01-create-a-website.md +0 -36
- package/docs/server/04-web/02-list-websites.md +0 -9
- package/docs/server/04-web/03-delete-a-website.md +0 -29
- package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
- package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
- package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
- package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
- package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
- package/docs/server/07-mail/04-change-account-password.md +0 -23
- package/framework/src/Candy.js +0 -81
- package/framework/src/Route.js +0 -455
- package/framework/src/Server.js +0 -15
- package/locale/de-DE.json +0 -80
- package/locale/en-US.json +0 -79
- package/locale/es-ES.json +0 -80
- package/locale/fr-FR.json +0 -80
- package/locale/pt-BR.json +0 -80
- package/locale/ru-RU.json +0 -80
- package/locale/tr-TR.json +0 -85
- package/locale/zh-CN.json +0 -80
- package/server/index.js +0 -5
- package/server/src/Api.js +0 -88
- package/server/src/DNS.js +0 -940
- package/server/src/Hub.js +0 -535
- package/server/src/Mail.js +0 -571
- package/server/src/SSL.js +0 -180
- package/server/src/Server.js +0 -27
- package/server/src/Service.js +0 -248
- package/server/src/Subdomain.js +0 -64
- package/server/src/Web/Firewall.js +0 -170
- package/server/src/Web/Proxy.js +0 -134
- package/server/src/Web.js +0 -451
- package/server/src/mail/imap.js +0 -1091
- package/server/src/mail/server.js +0 -32
- package/server/src/mail/smtp.js +0 -786
- package/test/server/Client.test.js +0 -338
- package/test/server/__mocks__/http-proxy.js +0 -105
- package/watchdog/index.js +0 -3
- package/watchdog/src/Watchdog.js +0 -156
- package/web/config.json +0 -5
- package/web/view/footer/main.html +0 -11
- /package/{framework/src → src}/Env.js +0 -0
- /package/{framework/src → src}/Route/Cron.js +0 -0
- /package/{framework/src → src}/Token.js +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
## ✅ The `Validator` Service
|
|
2
2
|
|
|
3
|
-
The Validator service provides a fluent, chainable API for validating user input. It's automatically available in your controllers through `
|
|
3
|
+
The Validator service provides a fluent, chainable API for validating user input. It's automatically available in your controllers through `Odac.Validator`.
|
|
4
4
|
|
|
5
5
|
#### Basic Usage
|
|
6
6
|
|
|
7
7
|
The validator uses a method-chaining pattern:
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
|
-
const validator =
|
|
10
|
+
const validator = Odac.Validator
|
|
11
11
|
validator.post('email').check('required|email').message('Valid email required')
|
|
12
12
|
validator.post('password').check('required|minlen:8').message('Password must be at least 8 characters')
|
|
13
13
|
|
|
@@ -82,8 +82,8 @@ Use `!` prefix to invert any rule: `!required`, `!email`, etc.
|
|
|
82
82
|
#### Example: User Registration
|
|
83
83
|
|
|
84
84
|
```javascript
|
|
85
|
-
module.exports = async function (
|
|
86
|
-
const validator =
|
|
85
|
+
module.exports = async function (Odac) {
|
|
86
|
+
const validator = Odac.Validator
|
|
87
87
|
|
|
88
88
|
validator.post('username').check('required|username|minlen:4|maxlen:20').message('Username must be 4-20 alphanumeric characters')
|
|
89
89
|
validator.post('email').check('required|email').message('Valid email address required')
|
|
@@ -101,8 +101,8 @@ module.exports = async function (Candy) {
|
|
|
101
101
|
#### Example: Login with Brute Force Protection
|
|
102
102
|
|
|
103
103
|
```javascript
|
|
104
|
-
module.exports = async function (
|
|
105
|
-
const validator =
|
|
104
|
+
module.exports = async function (Odac) {
|
|
105
|
+
const validator = Odac.Validator
|
|
106
106
|
|
|
107
107
|
validator.post('email').check('required|email').message('Email required')
|
|
108
108
|
validator.post('password').check('required').message('Password required')
|
|
@@ -119,8 +119,8 @@ module.exports = async function (Candy) {
|
|
|
119
119
|
#### Example: Custom Variable Validation
|
|
120
120
|
|
|
121
121
|
```javascript
|
|
122
|
-
module.exports = async function (
|
|
123
|
-
const validator =
|
|
122
|
+
module.exports = async function (Odac) {
|
|
123
|
+
const validator = Odac.Validator
|
|
124
124
|
const customValue = calculateSomething()
|
|
125
125
|
|
|
126
126
|
validator.var('calculated_value', customValue).check('numeric|min:100|max:1000').message('Value must be between 100 and 1000')
|
|
@@ -138,8 +138,8 @@ module.exports = async function (Candy) {
|
|
|
138
138
|
You can chain multiple `check()` calls for the same field, each with its own specific error message. The validator will return the first error it encounters:
|
|
139
139
|
|
|
140
140
|
```javascript
|
|
141
|
-
module.exports = async function (
|
|
142
|
-
const validator =
|
|
141
|
+
module.exports = async function (Odac) {
|
|
142
|
+
const validator = Odac.Validator
|
|
143
143
|
|
|
144
144
|
validator
|
|
145
145
|
.post('password')
|
|
@@ -160,8 +160,8 @@ module.exports = async function (Candy) {
|
|
|
160
160
|
#### Example: Complex Form Validation
|
|
161
161
|
|
|
162
162
|
```javascript
|
|
163
|
-
module.exports = async function (
|
|
164
|
-
const validator =
|
|
163
|
+
module.exports = async function (Odac) {
|
|
164
|
+
const validator = Odac.Validator
|
|
165
165
|
|
|
166
166
|
validator
|
|
167
167
|
.post('username')
|
|
@@ -203,8 +203,8 @@ module.exports = async function (Candy) {
|
|
|
203
203
|
#### Example: Date Range Validation
|
|
204
204
|
|
|
205
205
|
```javascript
|
|
206
|
-
module.exports = async function (
|
|
207
|
-
const validator =
|
|
206
|
+
module.exports = async function (Odac) {
|
|
207
|
+
const validator = Odac.Validator
|
|
208
208
|
|
|
209
209
|
validator
|
|
210
210
|
.post('start_date')
|
|
@@ -229,10 +229,10 @@ module.exports = async function (Candy) {
|
|
|
229
229
|
#### Example: Conditional Validation with Custom Variables
|
|
230
230
|
|
|
231
231
|
```javascript
|
|
232
|
-
module.exports = async function (
|
|
233
|
-
const validator =
|
|
234
|
-
const userRole =
|
|
235
|
-
const userCredits =
|
|
232
|
+
module.exports = async function (Odac) {
|
|
233
|
+
const validator = Odac.Validator
|
|
234
|
+
const userRole = Odac.Auth.user('role')
|
|
235
|
+
const userCredits = Odac.Auth.user('credits') || 0
|
|
236
236
|
|
|
237
237
|
validator.post('title').check('required').message('Title is required')
|
|
238
238
|
validator.post('content').check('required').message('Content is required')
|
|
@@ -263,8 +263,8 @@ module.exports = async function (Candy) {
|
|
|
263
263
|
#### Example: User Authentication Validation
|
|
264
264
|
|
|
265
265
|
```javascript
|
|
266
|
-
module.exports = async function (
|
|
267
|
-
const validator =
|
|
266
|
+
module.exports = async function (Odac) {
|
|
267
|
+
const validator = Odac.Validator
|
|
268
268
|
|
|
269
269
|
validator
|
|
270
270
|
.post('current_password')
|
|
@@ -290,9 +290,9 @@ module.exports = async function (Candy) {
|
|
|
290
290
|
You can use boolean values directly in `check()` for custom validation logic:
|
|
291
291
|
|
|
292
292
|
```javascript
|
|
293
|
-
module.exports = async function (
|
|
294
|
-
const validator =
|
|
295
|
-
const userId = await
|
|
293
|
+
module.exports = async function (Odac) {
|
|
294
|
+
const validator = Odac.Validator
|
|
295
|
+
const userId = await Odac.request('user_id')
|
|
296
296
|
|
|
297
297
|
const isOwner = await checkIfUserOwnsResource(userId)
|
|
298
298
|
const hasPermission = await checkUserPermission('edit')
|
|
@@ -323,8 +323,8 @@ module.exports = async function (Candy) {
|
|
|
323
323
|
#### Example: Chained Validation (Single Statement)
|
|
324
324
|
|
|
325
325
|
```javascript
|
|
326
|
-
module.exports = async function (
|
|
327
|
-
return await
|
|
326
|
+
module.exports = async function (Odac) {
|
|
327
|
+
return await Odac.Validator
|
|
328
328
|
.post('email').check('required').message('Email required').check('email').message('Invalid email')
|
|
329
329
|
.post('password').check('required').message('Password required').check('minlen:8').message('Min 8 chars')
|
|
330
330
|
.post('age').check('required').message('Age required').check('numeric').message('Must be number').check('min:18').message('Must be 18+')
|
|
@@ -335,8 +335,8 @@ module.exports = async function (Candy) {
|
|
|
335
335
|
#### Example: Admin-Only Action with User Check
|
|
336
336
|
|
|
337
337
|
```javascript
|
|
338
|
-
module.exports = async function (
|
|
339
|
-
const validator =
|
|
338
|
+
module.exports = async function (Odac) {
|
|
339
|
+
const validator = Odac.Validator
|
|
340
340
|
|
|
341
341
|
validator
|
|
342
342
|
.var('auth_check', null)
|
|
@@ -359,39 +359,39 @@ module.exports = async function (Candy) {
|
|
|
359
359
|
|
|
360
360
|
#### Frontend Integration
|
|
361
361
|
|
|
362
|
-
When using `
|
|
362
|
+
When using `Odac.form()` on the frontend, validation errors are automatically displayed:
|
|
363
363
|
|
|
364
364
|
**Automatic Error Display:**
|
|
365
|
-
- Each field's error message appears below the input with attribute `[
|
|
366
|
-
- Invalid inputs get the `
|
|
365
|
+
- Each field's error message appears below the input with attribute `[odac-form-error="fieldname"]`
|
|
366
|
+
- Invalid inputs get the `_odac_error` CSS class automatically
|
|
367
367
|
- Errors fade out when the user focuses on the input
|
|
368
368
|
|
|
369
369
|
**Success Messages:**
|
|
370
|
-
- Success messages appear in elements with `[
|
|
370
|
+
- Success messages appear in elements with `[odac-form-success]` attribute
|
|
371
371
|
- Automatically fades in when validation passes
|
|
372
372
|
|
|
373
373
|
**Auto-Redirect:**
|
|
374
|
-
- If you pass a URL as the second parameter to `
|
|
374
|
+
- If you pass a URL as the second parameter to `Odac.form()`, successful submissions automatically redirect:
|
|
375
375
|
```javascript
|
|
376
|
-
|
|
376
|
+
Odac.form('myForm', '/dashboard') // Redirects to /dashboard on success
|
|
377
377
|
```
|
|
378
378
|
|
|
379
379
|
**Example HTML:**
|
|
380
380
|
```html
|
|
381
|
-
<form
|
|
381
|
+
<form odac-form="register" action="/api/register" method="POST">
|
|
382
382
|
<input type="email" name="email" placeholder="Email">
|
|
383
|
-
<span
|
|
383
|
+
<span odac-form-error="email"></span>
|
|
384
384
|
|
|
385
385
|
<input type="password" name="password" placeholder="Password">
|
|
386
|
-
<span
|
|
386
|
+
<span odac-form-error="password"></span>
|
|
387
387
|
|
|
388
388
|
<button type="submit">Register</button>
|
|
389
389
|
|
|
390
|
-
<span
|
|
390
|
+
<span odac-form-success></span>
|
|
391
391
|
</form>
|
|
392
392
|
|
|
393
393
|
<script>
|
|
394
|
-
|
|
394
|
+
Odac.form('register', '/dashboard') // Auto-redirect on success
|
|
395
395
|
</script>
|
|
396
396
|
```
|
|
397
397
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
## 🔐 User Logins with `Auth.js`
|
|
2
2
|
|
|
3
|
-
The `
|
|
3
|
+
The `Odac.Auth` service is your bouncer, managing who gets in and who stays out. It handles user login sessions for you.
|
|
4
4
|
|
|
5
5
|
#### Letting a User In
|
|
6
6
|
|
|
7
|
-
`
|
|
7
|
+
`Odac.Auth.login(userId, userData)`
|
|
8
8
|
|
|
9
9
|
* `userId`: A unique ID for the user (like their database ID).
|
|
10
10
|
* `userData`: An object with any user info you want to remember, like their username or role.
|
|
@@ -13,41 +13,41 @@ When you call this, `Auth` creates a secure session for the user.
|
|
|
13
13
|
|
|
14
14
|
#### Checking the Guest List
|
|
15
15
|
|
|
16
|
-
* `
|
|
17
|
-
* `
|
|
18
|
-
* `
|
|
16
|
+
* `Odac.Auth.isLogin()`: Is the current user logged in? Returns `true` or `false`.
|
|
17
|
+
* `Odac.Auth.getId()`: Gets the ID of the logged-in user.
|
|
18
|
+
* `Odac.Auth.get('some-key')`: Grabs a specific piece of info from the `userData` you stored.
|
|
19
19
|
|
|
20
20
|
#### Showing a User Out
|
|
21
21
|
|
|
22
|
-
* `
|
|
22
|
+
* `Odac.Auth.logout()`: Ends the user's session and logs them out.
|
|
23
23
|
|
|
24
24
|
#### Example: A Login Flow
|
|
25
25
|
```javascript
|
|
26
26
|
// Controller for your login form
|
|
27
|
-
module.exports = async function (
|
|
28
|
-
const { username, password } =
|
|
27
|
+
module.exports = async function (Odac) {
|
|
28
|
+
const { username, password } = Odac.Request.post;
|
|
29
29
|
|
|
30
30
|
// IMPORTANT: You need to write your own code to find the user in your database!
|
|
31
31
|
const user = await yourDatabase.findUser(username, password);
|
|
32
32
|
|
|
33
33
|
if (user) {
|
|
34
34
|
// User is valid! Log them in.
|
|
35
|
-
|
|
36
|
-
return
|
|
35
|
+
Odac.Auth.login(user.id, { username: user.username });
|
|
36
|
+
return Odac.direct('/dashboard'); // Send them to their dashboard
|
|
37
37
|
} else {
|
|
38
38
|
// Bad credentials, send them back to the login page
|
|
39
|
-
return
|
|
39
|
+
return Odac.direct('/login?error=1');
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// A protected dashboard page
|
|
44
|
-
module.exports = function (
|
|
44
|
+
module.exports = function (Odac) {
|
|
45
45
|
// If they're not logged in, kick them back to the login page.
|
|
46
|
-
if (!
|
|
47
|
-
return
|
|
46
|
+
if (!Odac.Auth.isLogin()) {
|
|
47
|
+
return Odac.direct('/login');
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const username =
|
|
50
|
+
const username = Odac.Auth.get('username');
|
|
51
51
|
return `Welcome back, ${username}!`;
|
|
52
52
|
}
|
|
53
53
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## 🛡️ Foiling Villains with CSRF Protection
|
|
2
2
|
|
|
3
|
-
Cross-Site Request Forgery (CSRF) is a scary-sounding attack where a bad guy tries to trick your users into submitting forms they didn't mean to. The `
|
|
3
|
+
Cross-Site Request Forgery (CSRF) is a scary-sounding attack where a bad guy tries to trick your users into submitting forms they didn't mean to. The `Odac.Token` service is your shield against this!
|
|
4
4
|
|
|
5
5
|
#### How it Works
|
|
6
6
|
|
|
@@ -13,8 +13,8 @@ If they don't match, it's a trap!
|
|
|
13
13
|
|
|
14
14
|
#### Generating and Checking Tokens
|
|
15
15
|
|
|
16
|
-
* `
|
|
17
|
-
* `
|
|
16
|
+
* `Odac.Token.get()`: Creates a new secret token.
|
|
17
|
+
* `Odac.Token.check(theToken)`: Checks if `theToken` is valid.
|
|
18
18
|
|
|
19
19
|
#### Example: Securing a Form
|
|
20
20
|
|
|
@@ -31,22 +31,22 @@ If they don't match, it's a trap!
|
|
|
31
31
|
|
|
32
32
|
**2. Your controller that shows the form:**
|
|
33
33
|
```javascript
|
|
34
|
-
module.exports = function (
|
|
34
|
+
module.exports = function (Odac) {
|
|
35
35
|
// Get a token and pass it to the view
|
|
36
|
-
const token =
|
|
37
|
-
return
|
|
36
|
+
const token = Odac.Token.get();
|
|
37
|
+
return Odac.View.render('your_form_view', { csrfToken: token });
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
**3. Your controller that handles the form submission:**
|
|
42
42
|
```javascript
|
|
43
|
-
module.exports = function (
|
|
44
|
-
const submittedToken =
|
|
43
|
+
module.exports = function (Odac) {
|
|
44
|
+
const submittedToken = Odac.Request.post.csrf_token;
|
|
45
45
|
|
|
46
46
|
// Check the token!
|
|
47
|
-
if (!
|
|
47
|
+
if (!Odac.Token.check(submittedToken)) {
|
|
48
48
|
// If it's bad, stop right here.
|
|
49
|
-
return
|
|
49
|
+
return Odac.return('Invalid CSRF Token!').status(403);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// If we get here, the token was good!
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# User Registration
|
|
2
2
|
|
|
3
|
-
The `
|
|
3
|
+
The `Odac.Auth.register()` method provides a secure and user-friendly way to create new user accounts with automatic password hashing, duplicate checking, and optional auto-login.
|
|
4
4
|
|
|
5
5
|
## Basic Usage
|
|
6
6
|
|
|
7
7
|
```javascript
|
|
8
|
-
module.exports = async function (
|
|
9
|
-
const result = await
|
|
8
|
+
module.exports = async function (Odac) {
|
|
9
|
+
const result = await Odac.Auth.register({
|
|
10
10
|
email: 'user@example.com',
|
|
11
11
|
username: 'johndoe',
|
|
12
12
|
password: 'securePassword123',
|
|
@@ -24,7 +24,7 @@ module.exports = async function (Candy) {
|
|
|
24
24
|
## Advanced Options
|
|
25
25
|
|
|
26
26
|
```javascript
|
|
27
|
-
const result = await
|
|
27
|
+
const result = await Odac.Auth.register(
|
|
28
28
|
{
|
|
29
29
|
email: 'user@example.com',
|
|
30
30
|
username: 'johndoe',
|
|
@@ -77,8 +77,8 @@ const result = await Candy.Auth.register(
|
|
|
77
77
|
## Example Controller
|
|
78
78
|
|
|
79
79
|
```javascript
|
|
80
|
-
module.exports = async function (
|
|
81
|
-
const validator =
|
|
80
|
+
module.exports = async function (Odac) {
|
|
81
|
+
const validator = Odac.Validator
|
|
82
82
|
|
|
83
83
|
// Validate input
|
|
84
84
|
validator.post('email').check('required|email').message('A valid email is required')
|
|
@@ -90,20 +90,20 @@ module.exports = async function (Candy) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
// Get validated data
|
|
93
|
-
const email = await
|
|
94
|
-
const username = await
|
|
95
|
-
const password = await
|
|
96
|
-
const name = await
|
|
93
|
+
const email = await Odac.request('email')
|
|
94
|
+
const username = await Odac.request('username')
|
|
95
|
+
const password = await Odac.request('password')
|
|
96
|
+
const name = await Odac.request('name')
|
|
97
97
|
|
|
98
98
|
// Register user
|
|
99
|
-
const result = await
|
|
99
|
+
const result = await Odac.Auth.register(
|
|
100
100
|
{email, username, password, name},
|
|
101
101
|
{uniqueFields: ['email', 'username']}
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
if (result.success) {
|
|
105
105
|
// User is now registered and logged in
|
|
106
|
-
return
|
|
106
|
+
return Odac.direct('/dashboard')
|
|
107
107
|
} else {
|
|
108
108
|
// Show error message
|
|
109
109
|
return {error: result.error}
|