refactor: session and user
This commit is contained in:
parent
00f1654ed9
commit
61f1a5b1f2
|
@ -9,11 +9,15 @@
|
||||||
'@flecks/electron': {}
|
'@flecks/electron': {}
|
||||||
'@flecks/fleck': {}
|
'@flecks/fleck': {}
|
||||||
'@flecks/governor': {}
|
'@flecks/governor': {}
|
||||||
|
'@flecks/passport-local-react': {}
|
||||||
|
'@flecks/passport-local': {}
|
||||||
|
'@flecks/passport-react': {}
|
||||||
|
'@flecks/passport': {}
|
||||||
'@flecks/react': {}
|
'@flecks/react': {}
|
||||||
'@flecks/redis': {}
|
'@flecks/redis': {}
|
||||||
'@flecks/redux': {}
|
'@flecks/redux': {}
|
||||||
'@flecks/repl': {}
|
'@flecks/repl': {}
|
||||||
'@flecks/server': {}
|
'@flecks/server': {}
|
||||||
|
'@flecks/session': {}
|
||||||
'@flecks/socket': {}
|
'@flecks/socket': {}
|
||||||
'@flecks/user': {}
|
|
||||||
'@flecks/web': {}
|
'@flecks/web': {}
|
||||||
|
|
|
@ -25,8 +25,12 @@
|
||||||
"@flecks/redux": "*",
|
"@flecks/redux": "*",
|
||||||
"@flecks/repl": "*",
|
"@flecks/repl": "*",
|
||||||
"@flecks/server": "*",
|
"@flecks/server": "*",
|
||||||
|
"@flecks/session": "*",
|
||||||
"@flecks/socket": "*",
|
"@flecks/socket": "*",
|
||||||
"@flecks/user": "*",
|
"@flecks/passport": "*",
|
||||||
|
"@flecks/passport-local": "*",
|
||||||
|
"@flecks/passport-local-react": "*",
|
||||||
|
"@flecks/passport-react": "*",
|
||||||
"@flecks/web": "*"
|
"@flecks/web": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -114,3 +114,6 @@ dist
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
# copy-webpack-plugin charity
|
||||||
|
.git
|
3
packages/passport-local-react/build/flecks.config.js
Normal file
3
packages/passport-local-react/build/flecks.config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
dependencies: ['@flecks/passport-local', '@flecks/passport-react'],
|
||||||
|
};
|
|
@ -1,3 +1,3 @@
|
||||||
'@flecks/core': {}
|
'@flecks/core': {}
|
||||||
'@flecks/react': {}
|
|
||||||
'@flecks/fleck': {}
|
'@flecks/fleck': {}
|
||||||
|
'@flecks/react': {}
|
30
packages/passport-local-react/package.json
Normal file
30
packages/passport-local-react/package.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "@flecks/passport-local-react",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cha0s/flecks.git",
|
||||||
|
"directory": "packages/passport-local-react"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"version": "2.0.3",
|
||||||
|
"scripts": {
|
||||||
|
"build": "flecks build",
|
||||||
|
"clean": "flecks clean",
|
||||||
|
"lint": "flecks lint",
|
||||||
|
"postversion": "cp package.json dist",
|
||||||
|
"test": "flecks test"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@flecks/core": "^2.0.0",
|
||||||
|
"@flecks/passport-local": "^2.0.0",
|
||||||
|
"@flecks/react": "^2.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@flecks/fleck": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
9
packages/passport-local-react/src/index.js
Normal file
9
packages/passport-local-react/src/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import {React} from '@flecks/react';
|
||||||
|
|
||||||
|
import PassportLocalLogin from './login';
|
||||||
|
|
||||||
|
export const hooks = {
|
||||||
|
'@flecks/passport-react.strategies': () => ({
|
||||||
|
Email: React.createElement(PassportLocalLogin),
|
||||||
|
}),
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||||
import {React} from '@flecks/react';
|
import {React} from '@flecks/react';
|
||||||
|
|
||||||
function UserLocalLogin() {
|
function PassportLocalLogin() {
|
||||||
return (
|
return (
|
||||||
<form action="/auth/local" method="post">
|
<form action="/auth/local" method="post">
|
||||||
<label>
|
<label>
|
||||||
|
@ -17,13 +17,11 @@ function UserLocalLogin() {
|
||||||
<input type="checkbox" />
|
<input type="checkbox" />
|
||||||
<span>Remember me</span>
|
<span>Remember me</span>
|
||||||
</label>
|
</label>
|
||||||
<a href="/auth/forgot">Forgot password?</a>
|
<a href="/auth/local/forgot">Forgot password?</a>
|
||||||
</div>
|
</div>
|
||||||
<label>
|
<input type="submit" value="Sign in" />
|
||||||
<input type="submit" value="Sign in" />
|
|
||||||
</label>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default UserLocalLogin;
|
export default PassportLocalLogin;
|
119
packages/passport-local/.gitignore
vendored
Normal file
119
packages/passport-local/.gitignore
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# copy-webpack-plugin charity
|
||||||
|
.git
|
3
packages/passport-local/build/flecks.config.js
Normal file
3
packages/passport-local/build/flecks.config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
dependencies: ['@flecks/passport'],
|
||||||
|
};
|
31
packages/passport-local/package.json
Normal file
31
packages/passport-local/package.json
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "@flecks/passport-local",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cha0s/flecks.git",
|
||||||
|
"directory": "packages/passport-local"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"version": "2.0.3",
|
||||||
|
"scripts": {
|
||||||
|
"build": "flecks build",
|
||||||
|
"clean": "flecks clean",
|
||||||
|
"lint": "flecks lint",
|
||||||
|
"postversion": "cp package.json dist",
|
||||||
|
"test": "flecks test"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"server.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@flecks/core": "^2.0.3",
|
||||||
|
"@flecks/passport": "^2.0.3",
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
|
"passport-local": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@flecks/fleck": "^2.0.3"
|
||||||
|
}
|
||||||
|
}
|
45
packages/passport-local/src/server/index.js
Normal file
45
packages/passport-local/src/server/index.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import {randomBytes} from 'crypto';
|
||||||
|
|
||||||
|
import {Flecks} from '@flecks/core';
|
||||||
|
import LocalStrategy from 'passport-local';
|
||||||
|
|
||||||
|
export const hooks = {
|
||||||
|
'@flecks/db/server.models.decorate': Flecks.decorate(require.context('./models/decorators')),
|
||||||
|
'@flecks/passport.strategies': (passport, flecks) => ({
|
||||||
|
local: new LocalStrategy(
|
||||||
|
{usernameField: 'email'},
|
||||||
|
async (email, password, fn) => {
|
||||||
|
const {User} = flecks.db.Models;
|
||||||
|
try {
|
||||||
|
const user = await User.findOne({where: {email}});
|
||||||
|
fn(undefined, user && await user.validatePassword(password) && user);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
fn(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'@flecks/repl.commands': (flecks) => {
|
||||||
|
const {User} = flecks.db.Models;
|
||||||
|
return {
|
||||||
|
createUser: async (spec) => {
|
||||||
|
const [email, maybePassword] = spec.split(' ', 2);
|
||||||
|
const password = maybePassword || randomBytes(8).toString('hex');
|
||||||
|
const user = User.build({email});
|
||||||
|
await user.addHashedPassword(password);
|
||||||
|
await user.save();
|
||||||
|
},
|
||||||
|
resetPassword: async (email) => {
|
||||||
|
const password = randomBytes(8).toString('hex');
|
||||||
|
const user = await User.findOne({where: {email}});
|
||||||
|
if (user) {
|
||||||
|
await user.addHashedPassword(password);
|
||||||
|
await user.save();
|
||||||
|
return `\nNew password: ${password}\n\n`;
|
||||||
|
}
|
||||||
|
return 'User not found.\n';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
119
packages/passport-react/.gitignore
vendored
Normal file
119
packages/passport-react/.gitignore
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# copy-webpack-plugin charity
|
||||||
|
.git
|
3
packages/passport-react/build/flecks.config.js
Normal file
3
packages/passport-react/build/flecks.config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
dependencies: ['@flecks/passport', '@flecks/react'],
|
||||||
|
};
|
3
packages/passport-react/build/flecks.yml
Normal file
3
packages/passport-react/build/flecks.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
'@flecks/core': {}
|
||||||
|
'@flecks/fleck': {}
|
||||||
|
'@flecks/react': {}
|
31
packages/passport-react/package.json
Normal file
31
packages/passport-react/package.json
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "@flecks/passport-react",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cha0s/flecks.git",
|
||||||
|
"directory": "packages/passport-react"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"version": "2.0.3",
|
||||||
|
"scripts": {
|
||||||
|
"build": "flecks build",
|
||||||
|
"clean": "flecks clean",
|
||||||
|
"lint": "flecks lint",
|
||||||
|
"postversion": "cp package.json dist",
|
||||||
|
"test": "flecks test"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@flecks/core": "^2.0.0",
|
||||||
|
"@flecks/passport": "^2.0.0",
|
||||||
|
"@flecks/react": "^2.0.0",
|
||||||
|
"@flecks/redux": "^2.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@flecks/fleck": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
2
packages/passport-react/src/index.js
Normal file
2
packages/passport-react/src/index.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export {default as Login} from './login';
|
||||||
|
export {default as UserRequired} from './user-required';
|
24
packages/passport-react/src/login.jsx
Normal file
24
packages/passport-react/src/login.jsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import {React, useFlecks} from '@flecks/react';
|
||||||
|
import {
|
||||||
|
Tab,
|
||||||
|
Tabs,
|
||||||
|
TabList,
|
||||||
|
TabPanel,
|
||||||
|
} from '@flecks/react/tabs';
|
||||||
|
|
||||||
|
function Login() {
|
||||||
|
const flecks = useFlecks();
|
||||||
|
const strategies = Object.entries(flecks.invokeMergeUnique('@flecks/passport-react.strategies'));
|
||||||
|
return (
|
||||||
|
<Tabs>
|
||||||
|
<TabList>
|
||||||
|
{strategies.map(([tab]) => <Tab key={tab}>{tab}</Tab>)}
|
||||||
|
</TabList>
|
||||||
|
<div className="behaved__tab-panels">
|
||||||
|
{strategies.map(([tab, panel]) => <TabPanel key={tab}>{panel}</TabPanel>)}
|
||||||
|
</div>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Login;
|
|
@ -1,7 +1,7 @@
|
||||||
import {PropTypes, React} from '@flecks/react';
|
import {PropTypes, React} from '@flecks/react';
|
||||||
import {Navigate, useLocation} from '@flecks/react/router';
|
import {Navigate, useLocation} from '@flecks/react/router';
|
||||||
import {useSelector} from '@flecks/redux';
|
import {useSelector} from '@flecks/redux';
|
||||||
import {userIdSelector} from '@flecks/user/state';
|
import {userIdSelector} from '@flecks/passport';
|
||||||
|
|
||||||
function UserRequired({children, destination}) {
|
function UserRequired({children, destination}) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
119
packages/passport/.gitignore
vendored
Normal file
119
packages/passport/.gitignore
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# copy-webpack-plugin charity
|
||||||
|
.git
|
3
packages/passport/build/flecks.config.js
Normal file
3
packages/passport/build/flecks.config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
dependencies: ['@flecks/db', '@flecks/session'],
|
||||||
|
};
|
|
@ -1,15 +1,14 @@
|
||||||
{
|
{
|
||||||
"name": "@flecks/user",
|
"name": "@flecks/passport",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/cha0s/flecks.git",
|
"url": "https://github.com/cha0s/flecks.git",
|
||||||
"directory": "packages/user"
|
"directory": "packages/passport"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "flecks build",
|
"build": "flecks build",
|
||||||
"clean": "flecks clean",
|
"clean": "flecks clean",
|
||||||
|
@ -18,25 +17,17 @@
|
||||||
"test": "flecks test"
|
"test": "flecks test"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"client.js",
|
|
||||||
"index.js",
|
"index.js",
|
||||||
"local.js",
|
"server.js"
|
||||||
"local/server.js",
|
|
||||||
"server.js",
|
|
||||||
"session/server.js"
|
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^2.0.3",
|
||||||
"@flecks/react": "^2.0.3",
|
"@flecks/db": "^2.0.3",
|
||||||
"@flecks/redux": "^2.0.3",
|
"@flecks/redux": "^2.0.3",
|
||||||
"bcrypt": "^5.0.0",
|
"@flecks/session": "^2.0.3",
|
||||||
"express": "^4.17.1",
|
"passport": "^0.7.0"
|
||||||
"express-session": "1.17.1",
|
|
||||||
"passport": "0.4.1",
|
|
||||||
"passport-local": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-react": "^7.12.10",
|
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^2.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
10
packages/passport/src/index.js
Normal file
10
packages/passport/src/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import {Flecks} from '@flecks/core';
|
||||||
|
|
||||||
|
import {user, users} from './state';
|
||||||
|
|
||||||
|
export * from './state';
|
||||||
|
|
||||||
|
export const hooks = {
|
||||||
|
'@flecks/redux.slices': () => ({user, users}),
|
||||||
|
'@flecks/socket.packets': Flecks.provide(require.context('./packets')),
|
||||||
|
};
|
4
packages/passport/src/packets/logout.js
Normal file
4
packages/passport/src/packets/logout.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default (flecks) => {
|
||||||
|
const {Packet} = flecks.fleck('@flecks/socket');
|
||||||
|
return class Logout extends Packet {};
|
||||||
|
};
|
143
packages/passport/src/server/index.js
Normal file
143
packages/passport/src/server/index.js
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
import {D, Flecks} from '@flecks/core';
|
||||||
|
import passport from 'passport';
|
||||||
|
import LogOps from 'passport/lib/http/request';
|
||||||
|
|
||||||
|
const debug = D('@flecks/passport');
|
||||||
|
const debugSilly = debug.extend('silly');
|
||||||
|
|
||||||
|
export const hooks = {
|
||||||
|
'@flecks/core.config': () => ({
|
||||||
|
/**
|
||||||
|
* Path to redirect to after failed login.
|
||||||
|
*/
|
||||||
|
failureRedirect: '/',
|
||||||
|
/**
|
||||||
|
* Path to redirect to after logout.
|
||||||
|
*/
|
||||||
|
logoutRedirect: '/',
|
||||||
|
/**
|
||||||
|
* Path to redirect to after successful login.
|
||||||
|
*/
|
||||||
|
successRedirect: '/',
|
||||||
|
}),
|
||||||
|
'@flecks/core.mixin': (Flecks) => (
|
||||||
|
class FlecksWithSession extends Flecks {
|
||||||
|
|
||||||
|
passport;
|
||||||
|
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'@flecks/db/server.models': Flecks.provide(require.context('./models')),
|
||||||
|
'@flecks/socket.packets.decorate': Flecks.decorate(require.context('./packets/decorators')),
|
||||||
|
'@flecks/web/server.request.route': Flecks.priority(
|
||||||
|
(flecks) => (req, res, next) => {
|
||||||
|
flecks.passport.initialize(req, res, () => {
|
||||||
|
debugSilly('@flecks/web/server.request.route: passport.session()');
|
||||||
|
flecks.passport.session(req, res, () => {
|
||||||
|
if (!req.user) {
|
||||||
|
const {User} = flecks.db.Models;
|
||||||
|
req.user = new User();
|
||||||
|
req.user.id = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debugSilly('web user ID: %s', req.user.id);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{after: '@flecks/session/server'},
|
||||||
|
),
|
||||||
|
'@flecks/server.up': Flecks.priority(
|
||||||
|
async (flecks) => {
|
||||||
|
passport.serializeUser((user, fn) => fn(null, user.id));
|
||||||
|
passport.deserializeUser(async (id, fn) => {
|
||||||
|
const {User} = flecks.db.Models;
|
||||||
|
try {
|
||||||
|
fn(undefined, await User.findByPk(id));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
fn(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
flecks.passport = {
|
||||||
|
initialize: passport.initialize(),
|
||||||
|
session: passport.session(),
|
||||||
|
strategies: flecks.invokeMergeUnique('@flecks/passport.strategies', passport),
|
||||||
|
};
|
||||||
|
Object.entries(flecks.passport.strategies)
|
||||||
|
.forEach(([name, strategy]) => {
|
||||||
|
passport.use(name, strategy);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{before: '@flecks/web/server', after: ['@flecks/db/server', '@flecks/session/server']},
|
||||||
|
),
|
||||||
|
'@flecks/socket.intercom': () => ({
|
||||||
|
'@flecks/passport.users': async (sids, server) => {
|
||||||
|
const sockets = await server.sockets();
|
||||||
|
return sids
|
||||||
|
.filter((sid) => sockets.has(sid))
|
||||||
|
.reduce(
|
||||||
|
(r, sid) => ({
|
||||||
|
...r,
|
||||||
|
[sid]: sockets.get(sid).handshake.user.id,
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
'@flecks/socket/server.request.socket': Flecks.priority(
|
||||||
|
(flecks) => (socket, next) => {
|
||||||
|
const {req} = socket;
|
||||||
|
flecks.passport.initialize(req, undefined, () => {
|
||||||
|
flecks.passport.session(req, undefined, async () => {
|
||||||
|
if (!req.user) {
|
||||||
|
const {User} = flecks.db.Models;
|
||||||
|
req.user = new User();
|
||||||
|
req.user.id = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debugSilly('socket user ID: %s', req.user.id);
|
||||||
|
}
|
||||||
|
req.login = LogOps.logIn;
|
||||||
|
req.logIn = LogOps.logIn;
|
||||||
|
req.logout = LogOps.logOut;
|
||||||
|
req.logOut = LogOps.logOut;
|
||||||
|
req.isAuthenticated = LogOps.isAuthenticated;
|
||||||
|
req.isUnauthenticated = LogOps.isUnauthenticated;
|
||||||
|
await socket.join(`/u/${req.user.id}`);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{after: '@flecks/session/server', before: '@flecks/governor/server'},
|
||||||
|
),
|
||||||
|
'@flecks/web.routes': (flecks) => {
|
||||||
|
const {
|
||||||
|
failureRedirect,
|
||||||
|
logoutRedirect,
|
||||||
|
successRedirect,
|
||||||
|
} = flecks.get('@flecks/passport/server');
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
path: '/auth/logout',
|
||||||
|
middleware: (req, res) => {
|
||||||
|
req.logout();
|
||||||
|
res.redirect(logoutRedirect);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
Object.entries(flecks.passport.strategies)
|
||||||
|
.forEach(([name]) => {
|
||||||
|
routes.push(
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: `/auth/${name}`,
|
||||||
|
middleware: passport.authenticate(name, {failureRedirect, successRedirect}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return routes;
|
||||||
|
},
|
||||||
|
};
|
21
packages/passport/src/server/packets/decorators/logout.js
Normal file
21
packages/passport/src/server/packets/decorators/logout.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
export default (Logout, flecks) => {
|
||||||
|
const {ValidationError} = flecks.fleck('@flecks/socket');
|
||||||
|
return class ServerLogout extends Logout {
|
||||||
|
|
||||||
|
static async respond(packet, socket) {
|
||||||
|
const {req} = socket;
|
||||||
|
req.logout();
|
||||||
|
await new Promise((r, e) => {
|
||||||
|
req.session.save((error) => (error ? e(error) : r()));
|
||||||
|
});
|
||||||
|
socket.send(['Redirect', flecks.get('@flecks/passport/server.logoutRedirect')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static validate(packet, {req}) {
|
||||||
|
if (!req.user) {
|
||||||
|
throw new ValidationError({code: 400, reason: 'anonymous'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
|
@ -14,7 +14,7 @@ export const userSelector = createSelector(
|
||||||
);
|
);
|
||||||
|
|
||||||
const slice = createSlice({
|
const slice = createSlice({
|
||||||
name: '@flecks/user.user',
|
name: '@flecks/passport.user',
|
||||||
initialState: 0,
|
initialState: 0,
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(hydrateServer, (state, action) => {
|
builder.addCase(hydrateServer, (state, action) => {
|
|
@ -15,7 +15,7 @@ export const {
|
||||||
} = adapter.getSelectors((state) => state.users);
|
} = adapter.getSelectors((state) => state.users);
|
||||||
|
|
||||||
const slice = createSlice({
|
const slice = createSlice({
|
||||||
name: '@flecks/user.users',
|
name: '@flecks/passport.users',
|
||||||
initialState: adapter.getInitialState({
|
initialState: adapter.getInitialState({
|
||||||
entities: {0: {name: 'anonymous'}},
|
entities: {0: {name: 'anonymous'}},
|
||||||
ids: [0],
|
ids: [0],
|
|
@ -13,10 +13,10 @@ const RedisStore = ConnectRedis(session);
|
||||||
export const hooks = {
|
export const hooks = {
|
||||||
'@flecks/core.priority': (graph, hook) => {
|
'@flecks/core.priority': (graph, hook) => {
|
||||||
if ('@flecks/server.up' === hook) {
|
if ('@flecks/server.up' === hook) {
|
||||||
graph.addDependency('@flecks/user/session/server', '@flecks/redis/server');
|
graph.addDependency('@flecks/session/server', '@flecks/redis/server');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'@flecks/user.session': async (flecks) => {
|
'@flecks/session.config': async (flecks) => {
|
||||||
const client = createClient(flecks, {legacyMode: true});
|
const client = createClient(flecks, {legacyMode: true});
|
||||||
await client.connect();
|
await client.connect();
|
||||||
return {
|
return {
|
||||||
|
|
119
packages/session/.gitignore
vendored
Normal file
119
packages/session/.gitignore
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# copy-webpack-plugin charity
|
||||||
|
.git
|
30
packages/session/package.json
Normal file
30
packages/session/package.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "@flecks/session",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cha0s/flecks.git",
|
||||||
|
"directory": "packages/session"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"version": "2.0.3",
|
||||||
|
"scripts": {
|
||||||
|
"build": "flecks build",
|
||||||
|
"clean": "flecks clean",
|
||||||
|
"lint": "flecks lint",
|
||||||
|
"postversion": "cp package.json dist",
|
||||||
|
"test": "flecks test"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"server.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@flecks/core": "^2.0.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"express-session": "^1.17.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@flecks/fleck": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
62
packages/session/src/server.js
Normal file
62
packages/session/src/server.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import {D} from '@flecks/core';
|
||||||
|
import express from 'express';
|
||||||
|
import expressSession from 'express-session';
|
||||||
|
|
||||||
|
const debug = D('@flecks/session');
|
||||||
|
const debugSilly = debug.extend('silly');
|
||||||
|
|
||||||
|
export const hooks = {
|
||||||
|
'@flecks/core.config': () => ({
|
||||||
|
/**
|
||||||
|
* Set the cookie secret for session encryption.
|
||||||
|
*
|
||||||
|
* See: http://expressjs.com/en/resources/middleware/cookie-parser.html
|
||||||
|
*/
|
||||||
|
cookieSecret: (
|
||||||
|
'Set the FLECKS_ENV__flecks_session_server__cookieSecret environment variable!'
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'@flecks/core.mixin': (Flecks) => (
|
||||||
|
class FlecksWithSession extends Flecks {
|
||||||
|
|
||||||
|
session;
|
||||||
|
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'@flecks/web/server.request.route': (flecks) => {
|
||||||
|
const urle = express.urlencoded({extended: true});
|
||||||
|
return (req, res, next) => {
|
||||||
|
urle(req, res, (error) => {
|
||||||
|
if (error) {
|
||||||
|
next(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flecks.session(req, res, (error) => {
|
||||||
|
if (error) {
|
||||||
|
next(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debugSilly('web session ID: %s', req.session.id);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'@flecks/server.up': async (flecks) => {
|
||||||
|
flecks.session = expressSession({
|
||||||
|
resave: false,
|
||||||
|
sameSite: true,
|
||||||
|
saveUninitialized: false,
|
||||||
|
secret: flecks.get('@flecks/session/server.cookieSecret'),
|
||||||
|
...await flecks.invokeMergeAsync('@flecks/session.config'),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'@flecks/socket/server.request.socket': (flecks) => (socket, next) => {
|
||||||
|
flecks.session(socket.handshake, {}, () => {
|
||||||
|
const id = socket.handshake.session?.id;
|
||||||
|
socket.join(id);
|
||||||
|
debugSilly('socket session ID: %s', id);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,115 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
||||||
|
|
||||||
## [2.0.3](https://github.com/cha0s/flecks/compare/v2.0.2...v2.0.3) (2023-11-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* electron ([81fc978](https://github.com/cha0s/flecks/commit/81fc978da2b8d32e303d165fe7c2f6071ac8e741))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.0.2](https://github.com/cha0s/flecks/compare/v2.0.1...v2.0.2) (2023-11-22)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.0.1](https://github.com/cha0s/flecks/compare/v2.0.0...v2.0.1) (2023-11-22)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [2.0.0](https://github.com/cha0s/flecks/compare/v1.4.1...v2.0.0) (2023-11-22)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* UserRequired ([9b5f6f4](https://github.com/cha0s/flecks/commit/9b5f6f4818afaec76ee941c8d2c4795912234ee8))
|
|
||||||
* webpack 5 support ([288b368](https://github.com/cha0s/flecks/commit/288b368b9ff96be5ccb58bd811838a4a4bb6c48c))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.4.1](https://github.com/cha0s/flecks/compare/v1.4.0...v1.4.1) (2022-03-19)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.4.0](https://github.com/cha0s/flecks/compare/v1.3.0...v1.4.0) (2022-03-19)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.3.0](https://github.com/cha0s/flecks/compare/v1.2.1...v1.3.0) (2022-03-09)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.2.1](https://github.com/cha0s/flecks/compare/v1.2.0...v1.2.1) (2022-03-08)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.2.0](https://github.com/cha0s/flecks/compare/v1.1.1...v1.2.0) (2022-03-07)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **user:** redux hydration ([60ab421](https://github.com/cha0s/flecks/commit/60ab4219887daa2efc12ca26e02c76287a4fd779))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* docs ([5e2b825](https://github.com/cha0s/flecks/commit/5e2b8256205efc0280c8308cea3e64fa06fe16a9))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.1.1](https://github.com/cha0s/flecks/compare/v1.1.0...v1.1.1) (2022-02-28)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [1.1.0](https://github.com/cha0s/flecks/compare/v1.0.2...v1.1.0) (2022-02-28)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* babel in flecksrc ([dc60217](https://github.com/cha0s/flecks/commits/dc60217bd66d436eac6afe0e6d803f43a354bc6b))
|
|
||||||
* rich debugging ([545bfce](https://github.com/cha0s/flecks/commits/545bfce1ab602044041b370b413df62ae0cb9363))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [1.0.2](https://github.com/cha0s/flecks/compare/v1.0.1...v1.0.2) (2022-02-28)
|
|
||||||
|
|
||||||
**Note:** Version bump only for package @flecks/user
|
|
|
@ -1,10 +0,0 @@
|
||||||
export const hooks = {
|
|
||||||
/**
|
|
||||||
* Modify express-session configuration.
|
|
||||||
*
|
|
||||||
* See: https://www.npmjs.com/package/express-session
|
|
||||||
*/
|
|
||||||
'@flecks/user.session': () => ({
|
|
||||||
saveUninitialized: true,
|
|
||||||
}),
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
import {Logout} from './packets';
|
|
||||||
|
|
||||||
import {user, users} from './state';
|
|
||||||
|
|
||||||
export * from './state';
|
|
||||||
|
|
||||||
export const hooks = {
|
|
||||||
'@flecks/redux.slices': () => ({
|
|
||||||
user,
|
|
||||||
users,
|
|
||||||
}),
|
|
||||||
'@flecks/socket.packets': (flecks) => ({
|
|
||||||
Logout: Logout(flecks),
|
|
||||||
}),
|
|
||||||
};
|
|
|
@ -1,2 +0,0 @@
|
||||||
export {default as UserLocalLogin} from './user-local-login';
|
|
||||||
export {default as UserRequired} from './user-required';
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './components';
|
|
|
@ -1,71 +0,0 @@
|
||||||
import {randomBytes} from 'crypto';
|
|
||||||
|
|
||||||
import {Flecks} from '@flecks/core';
|
|
||||||
import passport from 'passport';
|
|
||||||
import LocalStrategy from 'passport-local';
|
|
||||||
|
|
||||||
export const hooks = {
|
|
||||||
'@flecks/core.config': () => ({
|
|
||||||
/**
|
|
||||||
* Path to redirect to after failed login.
|
|
||||||
*/
|
|
||||||
failureRedirect: '/',
|
|
||||||
/**
|
|
||||||
* Path to redirect to after successful login.
|
|
||||||
*/
|
|
||||||
successRedirect: '/',
|
|
||||||
}),
|
|
||||||
'@flecks/db/server.models.decorate': (
|
|
||||||
Flecks.decorate(require.context('./models/decorators', false, /\.js$/))
|
|
||||||
),
|
|
||||||
'@flecks/web.routes': (flecks) => {
|
|
||||||
const {failureRedirect, successRedirect} = flecks.get('@flecks/user/local/server');
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
method: 'post',
|
|
||||||
path: '/auth/local',
|
|
||||||
middleware: passport.authenticate('local', {failureRedirect, successRedirect}),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
'@flecks/repl.commands': (flecks) => {
|
|
||||||
const {User} = flecks.db.Models;
|
|
||||||
return {
|
|
||||||
createUser: async (spec) => {
|
|
||||||
const [email, maybePassword] = spec.split(' ', 2);
|
|
||||||
const password = maybePassword || randomBytes(8).toString('hex');
|
|
||||||
const user = User.build({email});
|
|
||||||
await user.addHashedPassword(password);
|
|
||||||
await user.save();
|
|
||||||
},
|
|
||||||
resetPassword: async (email) => {
|
|
||||||
const password = randomBytes(8).toString('hex');
|
|
||||||
const user = await User.findOne({where: {email}});
|
|
||||||
if (user) {
|
|
||||||
await user.addHashedPassword(password);
|
|
||||||
await user.save();
|
|
||||||
return `\nNew password: ${password}\n\n`;
|
|
||||||
}
|
|
||||||
return 'User not found.\n';
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
'@flecks/server.up': Flecks.priority(
|
|
||||||
(flecks) => {
|
|
||||||
passport.use(new LocalStrategy(
|
|
||||||
{usernameField: 'email'},
|
|
||||||
async (email, password, fn) => {
|
|
||||||
const {User} = flecks.db.Models;
|
|
||||||
try {
|
|
||||||
const user = await User.findOne({where: {email}});
|
|
||||||
fn(undefined, user && await user.validatePassword(password) && user);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
fn(error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
));
|
|
||||||
},
|
|
||||||
{after: '@flecks/user/server', before: '@flecks/repl/server'},
|
|
||||||
),
|
|
||||||
};
|
|
|
@ -1,2 +0,0 @@
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
|
||||||
export {default as Logout} from './logout';
|
|
|
@ -1,20 +0,0 @@
|
||||||
export default (flecks) => {
|
|
||||||
const {Packet, ValidationError} = flecks.fleck('@flecks/socket');
|
|
||||||
|
|
||||||
return class Logout extends Packet {
|
|
||||||
|
|
||||||
static respond(packet, {req}) {
|
|
||||||
req.logout();
|
|
||||||
return new Promise((r, e) => {
|
|
||||||
req.session.save((error) => (error ? e(error) : r()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static validate(packet, {req}) {
|
|
||||||
if (!req.user) {
|
|
||||||
throw new ValidationError({code: 400, reason: 'anonymous'});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,87 +0,0 @@
|
||||||
import {D, Flecks} from '@flecks/core';
|
|
||||||
import passport from 'passport';
|
|
||||||
import LogOps from 'passport/lib/http/request';
|
|
||||||
|
|
||||||
const debug = D('@flecks/user/passport');
|
|
||||||
const debugSilly = debug.extend('silly');
|
|
||||||
|
|
||||||
export const hooks = {
|
|
||||||
'@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
|
|
||||||
'@flecks/web/server.request.route': (flecks) => (req, res, next) => {
|
|
||||||
debugSilly('@flecks/web/server.request.route: passport.initialize()');
|
|
||||||
passport.initialize()(req, res, () => {
|
|
||||||
debugSilly('@flecks/web/server.request.route: passport.session()');
|
|
||||||
passport.session()(req, res, () => {
|
|
||||||
if (!req.user) {
|
|
||||||
const {User} = flecks.db.Models;
|
|
||||||
req.user = new User();
|
|
||||||
req.user.id = 0;
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'@flecks/web.routes': () => [
|
|
||||||
{
|
|
||||||
method: 'get',
|
|
||||||
path: '/auth/logout',
|
|
||||||
middleware: (req, res) => {
|
|
||||||
req.logout();
|
|
||||||
res.redirect('/');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@flecks/server.up': Flecks.priority(
|
|
||||||
(flecks) => {
|
|
||||||
passport.serializeUser((user, fn) => fn(null, user.id));
|
|
||||||
passport.deserializeUser(async (id, fn) => {
|
|
||||||
const {User} = flecks.db.Models;
|
|
||||||
try {
|
|
||||||
fn(undefined, await User.findByPk(id));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
fn(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{before: '@flecks/web/server', after: ['@flecks/db/server', '@flecks/governor/server']},
|
|
||||||
),
|
|
||||||
'@flecks/socket.intercom': () => ({
|
|
||||||
'@flecks/user.users': async (sids, server) => {
|
|
||||||
const sockets = await server.sockets();
|
|
||||||
return sids
|
|
||||||
.filter((sid) => sockets.has(sid))
|
|
||||||
.reduce(
|
|
||||||
(r, sid) => ({
|
|
||||||
...r,
|
|
||||||
[sid]: sockets.get(sid).handshake.user.id,
|
|
||||||
}),
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
'@flecks/socket/server.request.socket': Flecks.priority(
|
|
||||||
(flecks) => (socket, next) => {
|
|
||||||
debugSilly('@flecks/socket/server.request.socket: passport.initialize()');
|
|
||||||
passport.initialize()(socket.handshake, undefined, () => {
|
|
||||||
debugSilly('@flecks/socket/server.request.socket: passport.session()');
|
|
||||||
passport.session()(socket.handshake, undefined, async () => {
|
|
||||||
if (!socket.handshake.user) {
|
|
||||||
const {User} = flecks.db.Models;
|
|
||||||
socket.handshake.user = new User();
|
|
||||||
socket.handshake.user.id = 0;
|
|
||||||
}
|
|
||||||
socket.handshake.login = LogOps.logIn;
|
|
||||||
socket.handshake.logIn = LogOps.logIn;
|
|
||||||
socket.handshake.logout = LogOps.logOut;
|
|
||||||
socket.handshake.logOut = LogOps.logOut;
|
|
||||||
socket.handshake.isAuthenticated = LogOps.isAuthenticated;
|
|
||||||
socket.handshake.isUnauthenticated = LogOps.isUnauthenticated;
|
|
||||||
await socket.join(`/u/${socket.handshake.user.id}`);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{before: '@flecks/governor/server'},
|
|
||||||
),
|
|
||||||
};
|
|
|
@ -1,75 +0,0 @@
|
||||||
import {D, Flecks} from '@flecks/core';
|
|
||||||
import express from 'express';
|
|
||||||
import expressSession from 'express-session';
|
|
||||||
|
|
||||||
const debug = D('@flecks/user/session');
|
|
||||||
const debugSilly = debug.extend('silly');
|
|
||||||
|
|
||||||
export const hooks = {
|
|
||||||
'@flecks/core.config': () => ({
|
|
||||||
/**
|
|
||||||
* Set the cookie secret for session encryption.
|
|
||||||
*
|
|
||||||
* See: http://expressjs.com/en/resources/middleware/cookie-parser.html
|
|
||||||
*/
|
|
||||||
cookieSecret: (
|
|
||||||
'Set the FLECKS_ENV__flecks_user_session_server__cookieSecret environment variable!'
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
'@flecks/core.mixin': (Flecks) => (
|
|
||||||
class FlecksWithUser extends Flecks {
|
|
||||||
|
|
||||||
user = {
|
|
||||||
session: undefined,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
),
|
|
||||||
'@flecks/web/server.request.route': Flecks.priority(
|
|
||||||
(flecks) => {
|
|
||||||
const urle = express.urlencoded({extended: true});
|
|
||||||
return (req, res, next) => {
|
|
||||||
debugSilly('@flecks/web/server.request.route: express.urlencoded()');
|
|
||||||
urle(req, res, (error) => {
|
|
||||||
if (error) {
|
|
||||||
next(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
debugSilly('@flecks/web/server.request.route: session()');
|
|
||||||
flecks.user.session(req, res, (error) => {
|
|
||||||
if (error) {
|
|
||||||
next(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
debugSilly('session ID: %s', req.session.id);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{before: '@flecks/user/server'},
|
|
||||||
),
|
|
||||||
'@flecks/server.up': Flecks.priority(
|
|
||||||
async (flecks) => {
|
|
||||||
flecks.user.session = expressSession({
|
|
||||||
resave: false,
|
|
||||||
sameSite: true,
|
|
||||||
saveUninitialized: false,
|
|
||||||
secret: flecks.get('@flecks/user/session/server.cookieSecret'),
|
|
||||||
...await flecks.invokeMergeAsync('@flecks/user.session'),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{after: ['@flecks/governor/server', '@flecks/user/server']},
|
|
||||||
),
|
|
||||||
'@flecks/socket/server.request.socket': Flecks.priority(
|
|
||||||
(flecks) => (socket, next) => {
|
|
||||||
debugSilly('@flecks/socket/server.request.socket: session()');
|
|
||||||
flecks.user.session(socket.handshake, {}, () => {
|
|
||||||
const id = socket.handshake.session?.id;
|
|
||||||
socket.join(id);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{before: '@flecks/user/server'},
|
|
||||||
),
|
|
||||||
};
|
|
|
@ -18,11 +18,11 @@ Our `flecks.yml` could be configured like so:
|
||||||
```yaml
|
```yaml
|
||||||
'@flecks/http/server':
|
'@flecks/http/server':
|
||||||
'request.route':
|
'request.route':
|
||||||
- '@flecks/user/session'
|
- '@flecks/session'
|
||||||
- '@my-app/dark-mode-check'
|
- '@my-app/dark-mode-check'
|
||||||
```
|
```
|
||||||
|
|
||||||
In this application, when `@flecks/http/server.request.route` is invoked, `@flecks/user/session`'s
|
In this application, when `@flecks/http/server.request.route` is invoked, `@flecks/session`'s
|
||||||
implementation is invoked (which reifies the user's session from cookies), followed by
|
implementation is invoked (which reifies the user's session from cookies), followed by
|
||||||
`@my-app/dark-mode-check`'s.
|
`@my-app/dark-mode-check`'s.
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ provides you with the ellipses entry:
|
||||||
```yaml
|
```yaml
|
||||||
'@flecks/http/server':
|
'@flecks/http/server':
|
||||||
'request.route':
|
'request.route':
|
||||||
- '@flecks/user/session'
|
- '@flecks/session'
|
||||||
- '...'
|
- '...'
|
||||||
- '@my-app/finalize'
|
- '@my-app/finalize'
|
||||||
```
|
```
|
||||||
|
@ -71,7 +71,7 @@ export const hooks = {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then this is the same implementation but configured to run after `@flecks/user/session/server`:
|
Then this is the same implementation but configured to run after `@flecks/session/server`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export const hooks = {
|
export const hooks = {
|
||||||
|
@ -81,7 +81,7 @@ export const hooks = {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{after: '@flecks/user/session/server'},
|
{after: '@flecks/session/server'},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -227,7 +227,7 @@ const result = await socket.send(['Whatever']);
|
||||||
Whenever the client receives an `Action` packet, the action will be dispatched by
|
Whenever the client receives an `Action` packet, the action will be dispatched by
|
||||||
the redux store.
|
the redux store.
|
||||||
|
|
||||||
- `@flecks/user` implements a `validate` acceptor method for the `Logout` packet:
|
- `@flecks/passport` implements a `validate` acceptor method for the `Logout` packet:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
static validate(packet, {req}) {
|
static validate(packet, {req}) {
|
||||||
|
@ -247,7 +247,7 @@ parameters:
|
||||||
|
|
||||||
### `type`
|
### `type`
|
||||||
|
|
||||||
The type of intercom call to make (e.g. `@flecks/user.users`).
|
The type of intercom call to make (e.g. `@flecks/passport.users`).
|
||||||
|
|
||||||
### `data`
|
### `data`
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user