kreftjs 0.0.9-beta → 0.0.10-beta
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/bin/backend/index.js +4 -0
- package/bin/build.js +3 -2
- package/docs/README.md +15 -4
- package/kreftjs.d.ts +1 -1
- package/kreftjs.js +15 -2
- package/package.json +2 -2
- package/templates/app/_env.example +5 -4
- package/templates/app/backend/app/Http/Controllers/Auth/NewPasswordController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/Auth/RegisteredUserController.js +1 -1
- package/templates/app/backend/app/Http/Controllers/ProfileController.js +1 -1
- package/templates/app/backend/lang/ar/validation.json +2 -2
- package/templates/app/backend/lang/en/validation.json +2 -2
- package/templates/app/frontend/errors/ErrorMonitor.kreft +2 -2
- package/templates/app/frontend/kreftjs.d.ts +1 -1
- package/templates/app/frontend/kreftjs.js +15 -2
- package/templates/app/frontend/pages/Dashboard.kreft +1 -1
- package/templates/app/frontend/pages/Profile.kreft +1 -1
- package/templates/app/frontend/pages/auth/Register.kreft +1 -1
- package/templates/app/frontend/pages/auth/ResetPassword.kreft +1 -1
- package/templates/app/lang/ar/validation.json +1 -1
- package/templates/app/lang/en/validation.json +1 -1
- package/templates/errors/ErrorMonitor.kreft +1 -1
package/bin/backend/index.js
CHANGED
|
@@ -90,6 +90,10 @@ const loadModuleAsync = async (file) => {
|
|
|
90
90
|
function createBackend(baseDir, { db = null, production = false, log = console, prefix = '/api' } = {}) {
|
|
91
91
|
const isProd = Boolean(production || process.env.APP_ENV === 'production' || process.env.NODE_ENV === 'production');
|
|
92
92
|
const isDebug = process.env.APP_DEBUG !== undefined ? (process.env.APP_DEBUG === 'true' || process.env.APP_DEBUG === '1') : !isProd;
|
|
93
|
+
// .env from an older template says SESSION_SECURE_COOKIE=false: in production that sends the session cookie over plain HTTP too
|
|
94
|
+
if (isProd && process.env.SESSION_SECURE_COOKIE === 'false') {
|
|
95
|
+
log.warn(' SECURITY: SESSION_SECURE_COOKIE=false in production. The login cookie is also sent over plain http://. Remove that line from .env (cookies are Secure in production by default).');
|
|
96
|
+
}
|
|
93
97
|
const { startAutoGarbageCollector } = require('./gc.js');
|
|
94
98
|
startAutoGarbageCollector({ thresholdMB: Number(process.env.AUTO_GC_THRESHOLD_MB) || 200, log: !isProd && process.env.VERBOSE_GC === '1' });
|
|
95
99
|
installAlias();
|
package/bin/build.js
CHANGED
|
@@ -253,7 +253,8 @@ ${indent(components.join('\n\n'))}
|
|
|
253
253
|
};
|
|
254
254
|
|
|
255
255
|
// Apache (Hostinger, cPanel …) answers /docs with a 404, because only index.html exists on disk. These rules send every page address
|
|
256
|
-
// (no file extension, not under /api/) that is not a real file or folder
|
|
256
|
+
// (no file extension, not under /api/) that is not a real file, or a folder with its own index.html (a prerendered page), to index.html,
|
|
257
|
+
// so reloading a page works even when a folder has the page's name (the docs/ folder next to the /docs page). A missing file such as
|
|
257
258
|
// app.js, or an /api/ address the host cannot answer, stays a real 404: sending it index.html would hand the page's HTML to code
|
|
258
259
|
// that expects data (a list, JSON). An .htaccess you keep in public/ is left alone;
|
|
259
260
|
// a relative base (./, as the desktop build uses) has no server and gets no file.
|
|
@@ -267,7 +268,7 @@ function writeHtaccess(dist, html) {
|
|
|
267
268
|
RewriteBase ${base}
|
|
268
269
|
RewriteRule ^index\\.html$ - [L]
|
|
269
270
|
RewriteCond %{REQUEST_FILENAME} !-f
|
|
270
|
-
RewriteCond %{REQUEST_FILENAME} !-
|
|
271
|
+
RewriteCond %{REQUEST_FILENAME}/index.html !-f
|
|
271
272
|
RewriteCond %{REQUEST_URI} !^${base}api/
|
|
272
273
|
RewriteCond %{REQUEST_URI} !\\.[A-Za-z0-9]+$
|
|
273
274
|
RewriteRule . ${base}index.html [L]
|
package/docs/README.md
CHANGED
|
@@ -82,7 +82,7 @@ npx kreftjs dev
|
|
|
82
82
|
### Check that it works
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
kreft --version # for example 0.0.
|
|
85
|
+
kreft --version # for example 0.0.10-beta
|
|
86
86
|
kreft about # Kreft and Node.js versions, this project's settings and drivers
|
|
87
87
|
kreft list # every command your version has
|
|
88
88
|
```
|
|
@@ -1045,6 +1045,16 @@ Without a form, `validate(values, rules)` gives `{}` or `{ field: ['…'] }`. Cu
|
|
|
1045
1045
|
|
|
1046
1046
|
The same rule names work on the server in `req.validate()` (see [Controllers and requests](#controllers-and-requests)), so one set of rules can describe both sides.
|
|
1047
1047
|
|
|
1048
|
+
### Passwords
|
|
1049
|
+
|
|
1050
|
+
`not_common_password` refuses a password that is among the most used ones (`password`, `12345678`, `qwertyuiop` …), one character repeated (`aaaaaaaa`), a plain run (`12345678`, `abcdefgh`), or the same as the email address. A new app uses it next to `min:8` when people register, reset or change a password, in the pages and in the controllers:
|
|
1051
|
+
|
|
1052
|
+
```js
|
|
1053
|
+
password: 'required|min:8|confirmed|not_common_password'
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
It is a short list that runs offline, with no service called, so it catches the worst choices and nothing more. For longer ones, raise `min` (a passphrase of four words beats a short mix of symbols). Change the message in `lang/en/validation.json` (`not_common_password`).
|
|
1057
|
+
|
|
1048
1058
|
## Internationalization and RTL
|
|
1049
1059
|
|
|
1050
1060
|
Kreft translates text and flips direction for right-to-left languages such as Arabic, Hebrew, Persian and Urdu.
|
|
@@ -1735,13 +1745,13 @@ RewriteEngine On
|
|
|
1735
1745
|
RewriteBase /
|
|
1736
1746
|
RewriteRule ^index\.html$ - [L]
|
|
1737
1747
|
RewriteCond %{REQUEST_FILENAME} !-f
|
|
1738
|
-
RewriteCond %{REQUEST_FILENAME} !-
|
|
1748
|
+
RewriteCond %{REQUEST_FILENAME}/index.html !-f
|
|
1739
1749
|
RewriteCond %{REQUEST_URI} !^/api/
|
|
1740
1750
|
RewriteCond %{REQUEST_URI} !\.[A-Za-z0-9]+$
|
|
1741
1751
|
RewriteRule . /index.html [L]
|
|
1742
1752
|
```
|
|
1743
1753
|
|
|
1744
|
-
Apache only knows the files on disk, so without these rules `/docs` or any other clean address gives a 404 when someone opens or reloads it. With them, every page address (no file extension, not under `/api/`) that is not a real file or folder opens `index.html` and the router takes over. A missing file such as `app.js`, or an `/api/` address, stays a plain 404, so code that asks for data never receives the page's HTML. Upload the file too (it starts with a dot, so some file managers hide it; turn on "show hidden files"). If the site lives in a folder, build with `--base /folder/` and the rules follow it. An `.htaccess` you keep in `public/` is used as it is. A relative base (`--base ./`, used by the desktop build) gets no file.
|
|
1754
|
+
Apache only knows the files on disk, so without these rules `/docs` or any other clean address gives a 404 when someone opens or reloads it. With them, every page address (no file extension, not under `/api/`) that is not a real file, or a folder with its own `index.html`, opens `index.html` and the router takes over. A missing file such as `app.js`, or an `/api/` address, stays a plain 404, so code that asks for data never receives the page's HTML. Upload the file too (it starts with a dot, so some file managers hide it; turn on "show hidden files"). If the site lives in a folder, build with `--base /folder/` and the rules follow it. An `.htaccess` you keep in `public/` is used as it is. A relative base (`--base ./`, used by the desktop build) gets no file.
|
|
1745
1755
|
|
|
1746
1756
|
> [!NOTE]
|
|
1747
1757
|
> This hosts the front end only. Login, the database and everything under `/api` need the Node.js server, which Apache does not run.
|
|
@@ -2195,7 +2205,8 @@ Go through this before your first real user:
|
|
|
2195
2205
|
| `MCP_TOKEN` set, or MCP left off | The MCP endpoint is disabled in production without it. |
|
|
2196
2206
|
| Tables listed in `kreftjs.config.json`, or no `--db` at all | `kreft serve` serves only the tables you list. |
|
|
2197
2207
|
| No test user | Do not run `--seed` against production; delete `test@example.com` if it exists. |
|
|
2198
|
-
| HTTPS in front of the app | Cookies are `Secure` in production and on `https` URLs. |
|
|
2208
|
+
| HTTPS in front of the app, and `FORCE_HTTPS=true` | Cookies are `Secure` in production and on `https` URLs. Plain HTTP is only redirected to HTTPS with `FORCE_HTTPS=true` or an `https://` `APP_URL`. |
|
|
2209
|
+
| No `SESSION_SECURE_COOKIE=false` in `.env` | It switches the `Secure` flag off, so the login cookie is also sent over plain `http://`. Older templates wrote it; the server warns about it at start-up in production. |
|
|
2199
2210
|
| `npm audit` and `kreft update` | Fix known vulnerabilities before release. |
|
|
2200
2211
|
|
|
2201
2212
|
> [!NOTE]
|
package/kreftjs.d.ts
CHANGED
package/kreftjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.10-beta — reactive by nature
|
|
3
3
|
* The .kreft component language (state · derive · action · when · watch · on),
|
|
4
4
|
* { } views with k-if / k-each / k-model, components, slots, router, stores,
|
|
5
5
|
* share / receive, event bus and a template engine.
|
|
@@ -4678,6 +4678,7 @@
|
|
|
4678
4678
|
same: 'The :attribute field must match :other.',
|
|
4679
4679
|
different: 'The :attribute field and :other must be different.',
|
|
4680
4680
|
confirmed: 'The :attribute field confirmation does not match.',
|
|
4681
|
+
not_common_password: 'The :attribute is too common or too easy to guess. Choose another one.',
|
|
4681
4682
|
regex: 'The :attribute field format is invalid.',
|
|
4682
4683
|
digits: 'The :attribute field must be :digits digits.',
|
|
4683
4684
|
min: { string: 'The :attribute field must be at least :min characters.', numeric: 'The :attribute field must be at least :min.', array: 'The :attribute field must have at least :min items.' },
|
|
@@ -4687,6 +4688,17 @@
|
|
|
4687
4688
|
};
|
|
4688
4689
|
const isEmptyValue = (v) => v === undefined || v === null || (typeof v === 'string' && v.trim() === '') || (isArray(v) && !v.length);
|
|
4689
4690
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4691
|
+
// not_common_password: the passwords people choose most (8+ characters, so they pass `min:8`), one character repeated, a run like
|
|
4692
|
+
// 12345678 or abcdefgh, or the same as the email address. Not a replacement for a long passphrase.
|
|
4693
|
+
const COMMON_PASSWORDS = new Set('00000000 11111111 111111111 123123123 12345678 123456789 1234567890 12345678910 123456789a 123456abc 1q2w3e4r 1q2w3e4r5t 1qaz2wsx 88888888 987654321 abc12345 abcd1234 abcdefg1 abcdefgh admin123 admin1234 administrator asdfghjk asdfghjkl baseball1 changeme changeme1 dragon123 football1 freedom1 google123 hello123 hello1234 iloveyou iloveyou1 kreft123 kreftjs123 letmein1 letmein123 login123 master123 monkey123 p@ssw0rd p@ssword pass1234 passpass passw0rd password password1 password12 password123 password1234 princess1 qazwsxedc qwerty12 qwerty123 qwertyui qwertyuiop secret123 shadow123 starwars1 sunshine1 superman1 test1234 testing123 trustno1 welcome1 welcome123 whatever1 zxcvbnm1'.split(' '));
|
|
4694
|
+
const isCommonPassword = (v, data) => {
|
|
4695
|
+
const p = String(v).toLowerCase();
|
|
4696
|
+
if (COMMON_PASSWORDS.has(p) || /^(.)\1+$/.test(p)) return true;
|
|
4697
|
+
const runs = (s) => { let up = true, down = true; for (let i = 1; i < s.length; i++) { const d = s.charCodeAt(i) - s.charCodeAt(i - 1); if (d !== 1) up = false; if (d !== -1) down = false; } return up || down; };
|
|
4698
|
+
if (p.length >= 6 && runs(p)) return true;
|
|
4699
|
+
const email = data && typeof data.email === 'string' ? data.email.toLowerCase() : '';
|
|
4700
|
+
return Boolean(email) && (p === email || p === email.split('@')[0]);
|
|
4701
|
+
};
|
|
4690
4702
|
const dateOf = (v, data) => { const d = new Date(hasOwn(data, v) ? data[v] : v === 'today' ? new Date().toDateString() : v); return isNaN(d) ? null : d; };
|
|
4691
4703
|
function parseRules(rules) {
|
|
4692
4704
|
return (isArray(rules) ? rules : String(rules || '').split('|')).filter(Boolean).map((r) => {
|
|
@@ -4746,6 +4758,7 @@
|
|
|
4746
4758
|
case 'same': failed = value !== getPath(data, a); extra = { other: a.replace(/_/g, ' ') }; break;
|
|
4747
4759
|
case 'different': failed = value === getPath(data, a); extra = { other: a.replace(/_/g, ' ') }; break;
|
|
4748
4760
|
case 'confirmed': failed = value !== getPath(data, field + '_confirmation'); break;
|
|
4761
|
+
case 'not_common_password': failed = isCommonPassword(value, data); break;
|
|
4749
4762
|
case 'regex': { const m = r.arg.match(/^\/(.*)\/([a-z]*)$/); failed = !new RegExp(m ? m[1] : r.arg, m ? m[2] : '').test(String(value)); break; }
|
|
4750
4763
|
case 'digits': failed = !new RegExp(`^\\d{${Number(a)}}$`).test(String(value)); extra = { digits: a }; break;
|
|
4751
4764
|
case 'min': failed = sizeOf(value) < Number(a); extra = { min: a }; break;
|
|
@@ -5023,7 +5036,7 @@
|
|
|
5023
5036
|
stores, storeLog, busLog,
|
|
5024
5037
|
};
|
|
5025
5038
|
|
|
5026
|
-
const VERSION = '0.0.
|
|
5039
|
+
const VERSION = '0.0.10-beta';
|
|
5027
5040
|
const Kreftjs = {
|
|
5028
5041
|
version: VERSION,
|
|
5029
5042
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kreftjs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10-beta",
|
|
4
4
|
"description": "A tiny reactive framework with its own component language (.kreft files): router with nested routes, stores, saved data, animations, an API client, hot reload, DevTools and a template engine.",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"main": "kreftjs.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"start": "node bin/kreftjs.js dev --api demo/db.json --db sqlite:demo/database/demo.db --migrations demo/database/migrations --server demo/server --backend demo --seed",
|
|
15
15
|
"build": "node bin/kreftjs.js build demo --out dist/demo --include docs",
|
|
16
16
|
"preview": "node bin/kreftjs.js dev dist --api demo/db.json --db sqlite:demo/database/demo.db --migrations demo/database/migrations --server demo/server --backend demo --seed",
|
|
17
|
-
"test": "node --test test/security.test.js test/prerender.test.js test/seo.test.js test/rebrand.test.js test/noauth.test.js test/winspawn.test.js test/htaccess.test.js",
|
|
17
|
+
"test": "node --test test/security.test.js test/prerender.test.js test/seo.test.js test/rebrand.test.js test/noauth.test.js test/winspawn.test.js test/htaccess.test.js test/cookie-secure.test.js test/password-rule.test.js",
|
|
18
18
|
"electron": "kreftjs electron",
|
|
19
19
|
"electron:dev": "kreftjs electron:dev",
|
|
20
20
|
"electron:build": "kreftjs electron:build"
|
|
@@ -30,16 +30,17 @@ FILESYSTEM_DISK=local
|
|
|
30
30
|
# REDIS_PORT=6379
|
|
31
31
|
# REDIS_PASSWORD=
|
|
32
32
|
# REDIS_DB=0
|
|
33
|
-
# REDIS_PREFIX=
|
|
33
|
+
# REDIS_PREFIX=kreft:
|
|
34
34
|
# Environment & Debugging:
|
|
35
35
|
# - local: plain HTTP allowed on localhost, interactive bug diagnostics & stack traces shown
|
|
36
36
|
# - production: plain HTTP disallowed for security (enforces HTTPS & HSTS), bug details & stack traces hidden
|
|
37
37
|
APP_ENV=local
|
|
38
38
|
APP_DEBUG=true
|
|
39
39
|
|
|
40
|
-
#
|
|
41
|
-
FORCE_HTTPS=
|
|
42
|
-
|
|
40
|
+
# Redirect plain HTTP to HTTPS in production (with HSTS). Turn it on once the site has HTTPS:
|
|
41
|
+
# FORCE_HTTPS=true
|
|
42
|
+
# The login cookie is Secure in production and on an https:// APP_URL by itself. Do not set this to false in production:
|
|
43
|
+
# SESSION_SECURE_COOKIE=true
|
|
43
44
|
|
|
44
45
|
# Security & Sessions
|
|
45
46
|
# A login token nobody used for this many days stops working
|
|
@@ -10,7 +10,7 @@ class NewPasswordController {
|
|
|
10
10
|
const data = await req.validate({
|
|
11
11
|
token: 'required',
|
|
12
12
|
email: 'required|email',
|
|
13
|
-
password: 'required|min:8|confirmed',
|
|
13
|
+
password: 'required|min:8|confirmed|not_common_password',
|
|
14
14
|
})
|
|
15
15
|
const email = data.email.toLowerCase()
|
|
16
16
|
const row = await DB.table('password_reset_tokens').where('email', email).first()
|
|
@@ -8,7 +8,7 @@ class RegisteredUserController {
|
|
|
8
8
|
const data = await req.validate({
|
|
9
9
|
name: 'required|string|max:255',
|
|
10
10
|
email: 'required|string|email|max:255|unique:users,email',
|
|
11
|
-
password: 'required|min:8|confirmed',
|
|
11
|
+
password: 'required|min:8|confirmed|not_common_password',
|
|
12
12
|
})
|
|
13
13
|
const user = await User.create({ name: data.name, email: data.email.toLowerCase(), password: Hash.make(data.password) })
|
|
14
14
|
await user.sendEmailVerificationNotification()
|
|
@@ -42,7 +42,7 @@ class ProfileController {
|
|
|
42
42
|
if (req.accessToken && req.accessToken.type !== 'session' && !req.accessToken.can('*')) {
|
|
43
43
|
abort(403, 'Changing the account password requires a browser session.')
|
|
44
44
|
}
|
|
45
|
-
const data = await req.validate({ current_password: 'required|string|max:255', password: 'required|string|min:8|max:255|confirmed' })
|
|
45
|
+
const data = await req.validate({ current_password: 'required|string|max:255', password: 'required|string|min:8|max:255|confirmed|not_common_password' })
|
|
46
46
|
if (!Hash.check(data.current_password, req.user.password)) {
|
|
47
47
|
throw new ValidationError({ current_password: ['The password is incorrect.'] })
|
|
48
48
|
}
|
|
@@ -92,7 +92,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
92
92
|
<div class="badges">
|
|
93
93
|
<span class="badge danger-badge">HTTP {status}</span>
|
|
94
94
|
<span class="badge solid">{currentTitle}</span>
|
|
95
|
-
<span class="badge">Kreft {Kreftjs.version || '0.0.
|
|
95
|
+
<span class="badge">Kreft {Kreftjs.version || '0.0.10-beta'}</span>
|
|
96
96
|
</div>
|
|
97
97
|
<div class="actions">
|
|
98
98
|
<button class="sm" @click={copyReport}>{copied ? 'Copied Markdown' : 'Copy Report'}</button>
|
|
@@ -189,7 +189,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
189
189
|
<h3>Kreft Runtime</h3>
|
|
190
190
|
<table>
|
|
191
191
|
<tbody>
|
|
192
|
-
<tr><th>Engine</th><td><code>Kreft v{Kreftjs.version || '0.0.
|
|
192
|
+
<tr><th>Engine</th><td><code>Kreft v{Kreftjs.version || '0.0.10-beta'}</code></td></tr>
|
|
193
193
|
<tr><th>Sanitizer</th><td><code>Active (cleanHtml / SafeHtml)</code></td></tr>
|
|
194
194
|
<tr><th>Environment</th><td><code>development (APP_DEBUG=true)</code></td></tr>
|
|
195
195
|
</tbody>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.10-beta — reactive by nature
|
|
3
3
|
* The .kreft component language (state · derive · action · when · watch · on),
|
|
4
4
|
* { } views with k-if / k-each / k-model, components, slots, router, stores,
|
|
5
5
|
* share / receive, event bus and a template engine.
|
|
@@ -4678,6 +4678,7 @@
|
|
|
4678
4678
|
same: 'The :attribute field must match :other.',
|
|
4679
4679
|
different: 'The :attribute field and :other must be different.',
|
|
4680
4680
|
confirmed: 'The :attribute field confirmation does not match.',
|
|
4681
|
+
not_common_password: 'The :attribute is too common or too easy to guess. Choose another one.',
|
|
4681
4682
|
regex: 'The :attribute field format is invalid.',
|
|
4682
4683
|
digits: 'The :attribute field must be :digits digits.',
|
|
4683
4684
|
min: { string: 'The :attribute field must be at least :min characters.', numeric: 'The :attribute field must be at least :min.', array: 'The :attribute field must have at least :min items.' },
|
|
@@ -4687,6 +4688,17 @@
|
|
|
4687
4688
|
};
|
|
4688
4689
|
const isEmptyValue = (v) => v === undefined || v === null || (typeof v === 'string' && v.trim() === '') || (isArray(v) && !v.length);
|
|
4689
4690
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4691
|
+
// not_common_password: the passwords people choose most (8+ characters, so they pass `min:8`), one character repeated, a run like
|
|
4692
|
+
// 12345678 or abcdefgh, or the same as the email address. Not a replacement for a long passphrase.
|
|
4693
|
+
const COMMON_PASSWORDS = new Set('00000000 11111111 111111111 123123123 12345678 123456789 1234567890 12345678910 123456789a 123456abc 1q2w3e4r 1q2w3e4r5t 1qaz2wsx 88888888 987654321 abc12345 abcd1234 abcdefg1 abcdefgh admin123 admin1234 administrator asdfghjk asdfghjkl baseball1 changeme changeme1 dragon123 football1 freedom1 google123 hello123 hello1234 iloveyou iloveyou1 kreft123 kreftjs123 letmein1 letmein123 login123 master123 monkey123 p@ssw0rd p@ssword pass1234 passpass passw0rd password password1 password12 password123 password1234 princess1 qazwsxedc qwerty12 qwerty123 qwertyui qwertyuiop secret123 shadow123 starwars1 sunshine1 superman1 test1234 testing123 trustno1 welcome1 welcome123 whatever1 zxcvbnm1'.split(' '));
|
|
4694
|
+
const isCommonPassword = (v, data) => {
|
|
4695
|
+
const p = String(v).toLowerCase();
|
|
4696
|
+
if (COMMON_PASSWORDS.has(p) || /^(.)\1+$/.test(p)) return true;
|
|
4697
|
+
const runs = (s) => { let up = true, down = true; for (let i = 1; i < s.length; i++) { const d = s.charCodeAt(i) - s.charCodeAt(i - 1); if (d !== 1) up = false; if (d !== -1) down = false; } return up || down; };
|
|
4698
|
+
if (p.length >= 6 && runs(p)) return true;
|
|
4699
|
+
const email = data && typeof data.email === 'string' ? data.email.toLowerCase() : '';
|
|
4700
|
+
return Boolean(email) && (p === email || p === email.split('@')[0]);
|
|
4701
|
+
};
|
|
4690
4702
|
const dateOf = (v, data) => { const d = new Date(hasOwn(data, v) ? data[v] : v === 'today' ? new Date().toDateString() : v); return isNaN(d) ? null : d; };
|
|
4691
4703
|
function parseRules(rules) {
|
|
4692
4704
|
return (isArray(rules) ? rules : String(rules || '').split('|')).filter(Boolean).map((r) => {
|
|
@@ -4746,6 +4758,7 @@
|
|
|
4746
4758
|
case 'same': failed = value !== getPath(data, a); extra = { other: a.replace(/_/g, ' ') }; break;
|
|
4747
4759
|
case 'different': failed = value === getPath(data, a); extra = { other: a.replace(/_/g, ' ') }; break;
|
|
4748
4760
|
case 'confirmed': failed = value !== getPath(data, field + '_confirmation'); break;
|
|
4761
|
+
case 'not_common_password': failed = isCommonPassword(value, data); break;
|
|
4749
4762
|
case 'regex': { const m = r.arg.match(/^\/(.*)\/([a-z]*)$/); failed = !new RegExp(m ? m[1] : r.arg, m ? m[2] : '').test(String(value)); break; }
|
|
4750
4763
|
case 'digits': failed = !new RegExp(`^\\d{${Number(a)}}$`).test(String(value)); extra = { digits: a }; break;
|
|
4751
4764
|
case 'min': failed = sizeOf(value) < Number(a); extra = { min: a }; break;
|
|
@@ -5023,7 +5036,7 @@
|
|
|
5023
5036
|
stores, storeLog, busLog,
|
|
5024
5037
|
};
|
|
5025
5038
|
|
|
5026
|
-
const VERSION = '0.0.
|
|
5039
|
+
const VERSION = '0.0.10-beta';
|
|
5027
5040
|
const Kreftjs = {
|
|
5028
5041
|
version: VERSION,
|
|
5029
5042
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
|
@@ -112,7 +112,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
112
112
|
<div class="info-list">
|
|
113
113
|
<div class="info-item">
|
|
114
114
|
<span class="info-label">Framework Engine</span>
|
|
115
|
-
<span class="info-value">Kreft {Kreftjs.version || '0.0.
|
|
115
|
+
<span class="info-value">Kreft {Kreftjs.version || '0.0.10-beta'}</span>
|
|
116
116
|
</div>
|
|
117
117
|
<div class="info-item">
|
|
118
118
|
<span class="info-label">Active Database</span>
|
|
@@ -9,7 +9,7 @@ state info = form(
|
|
|
9
9
|
)
|
|
10
10
|
state pass = form(
|
|
11
11
|
{ current_password: '', password: '', password_confirmation: '' },
|
|
12
|
-
{ current_password: 'required', password: 'required|min:8|confirmed' },
|
|
12
|
+
{ current_password: 'required', password: 'required|min:8|confirmed|not_common_password' },
|
|
13
13
|
)
|
|
14
14
|
state saved = ''
|
|
15
15
|
state passSaved = ''
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- /register: make an account (POST /api/register, app/Http/Controllers/Auth/RegisteredUserController.js) -->
|
|
2
2
|
state f = form(
|
|
3
3
|
{ name: '', email: '', password: '', password_confirmation: '' },
|
|
4
|
-
{ name: 'required|max:255', email: 'required|email|max:255', password: 'required|min:8|confirmed' },
|
|
4
|
+
{ name: 'required|max:255', email: 'required|email|max:255', password: 'required|min:8|confirmed|not_common_password' },
|
|
5
5
|
)
|
|
6
6
|
state problem = ''
|
|
7
7
|
|
|
@@ -3,7 +3,7 @@ prop token = ''
|
|
|
3
3
|
|
|
4
4
|
state f = form(
|
|
5
5
|
{ email: $route.query.email || '', password: '', password_confirmation: '' },
|
|
6
|
-
{ email: 'required|email', password: 'required|min:8|confirmed' },
|
|
6
|
+
{ email: 'required|email', password: 'required|min:8|confirmed|not_common_password' },
|
|
7
7
|
)
|
|
8
8
|
state problem = ''
|
|
9
9
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"array": "يجب ألا يحتوي :attribute على أكثر من :max عناصر."
|
|
13
13
|
},
|
|
14
14
|
"confirmed": "تأكيد :attribute غير متطابق.",
|
|
15
|
+
"not_common_password": "كلمة :attribute شائعة جداً أو يسهل تخمينها. اختر كلمة أخرى.",
|
|
15
16
|
"attributes": {
|
|
16
17
|
"email": "البريد الإلكتروني",
|
|
17
18
|
"password": "كلمة المرور",
|
|
@@ -19,4 +20,3 @@
|
|
|
19
20
|
"title": "العنوان"
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
|
-
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"array": "The :attribute field must not have more than :max items."
|
|
13
13
|
},
|
|
14
14
|
"confirmed": "The :attribute confirmation does not match.",
|
|
15
|
+
"not_common_password": "The :attribute is too common or too easy to guess. Choose another one.",
|
|
15
16
|
"attributes": {
|
|
16
17
|
"email": "email address",
|
|
17
18
|
"password": "password",
|
|
@@ -19,4 +20,3 @@
|
|
|
19
20
|
"title": "title"
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
|
-
|
|
@@ -118,7 +118,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
118
118
|
<div class="hero-badges">
|
|
119
119
|
<span class="badge-exception">{currentTitle}</span>
|
|
120
120
|
<span class="badge-env">Node.js {typeof process !== 'undefined' ? process.version : 'v22.0.0'}</span>
|
|
121
|
-
<span class="badge-env">Kreft v0.0.
|
|
121
|
+
<span class="badge-env">Kreft v0.0.10-beta</span>
|
|
122
122
|
</div>
|
|
123
123
|
<h1 class="hero-error-message">{currentMessage}</h1>
|
|
124
124
|
</div>
|