mirror of
https://github.com/HeyPuter/puter.git
synced 2025-01-23 22:40:20 +08:00
Improve session mgmt (part 1)
This commit is contained in:
parent
eb66848aee
commit
e436693d3e
@ -17,35 +17,26 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
"use strict"
|
"use strict"
|
||||||
|
const APIError = require('../api/APIError');
|
||||||
const {jwt_auth} = require('../helpers');
|
const {jwt_auth} = require('../helpers');
|
||||||
|
const { UserActorType } = require('../services/auth/Actor');
|
||||||
const { DB_WRITE } = require('../services/database/consts');
|
const { DB_WRITE } = require('../services/database/consts');
|
||||||
const { Context } = require('../util/context');
|
const { Context } = require('../util/context');
|
||||||
|
const auth2 = require('./auth2');
|
||||||
|
|
||||||
const auth = async (req, res, next)=>{
|
const auth = async (req, res, next)=>{
|
||||||
|
let auth2_ok = false;
|
||||||
try{
|
try{
|
||||||
let auth_res = await jwt_auth(req);
|
// Delegate to new middleware
|
||||||
|
await auth2(req, res, () => { auth2_ok = true; });
|
||||||
|
if ( ! auth2_ok ) return;
|
||||||
|
|
||||||
// is account suspended?
|
// Everything using the old reference to the auth middleware
|
||||||
if(auth_res.user.suspended)
|
// should only allow session tokens
|
||||||
return res.status(401).send({error: 'Account suspended'});
|
if ( ! (req.actor.type instanceof UserActorType) ) {
|
||||||
|
throw APIError.create('forbidden');
|
||||||
// successful auth
|
|
||||||
req.user = auth_res.user;
|
|
||||||
req.token = auth_res.token;
|
|
||||||
|
|
||||||
// let's add it to the context too
|
|
||||||
try {
|
|
||||||
const x = Context.get();
|
|
||||||
x.set('user', req.user);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// record as daily active users
|
|
||||||
const db = req.services.get('database').get(DB_WRITE, 'auth');
|
|
||||||
db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [req.user.id]);
|
|
||||||
|
|
||||||
// go to next
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
// auth failed
|
// auth failed
|
||||||
|
0
packages/backend/src/routers/auth/list-sessions.js
Normal file
0
packages/backend/src/routers/auth/list-sessions.js
Normal file
@ -34,6 +34,8 @@ class AuthService extends BaseService {
|
|||||||
|
|
||||||
async _init () {
|
async _init () {
|
||||||
this.db = await this.services.get('database').get(DB_WRITE, 'auth');
|
this.db = await this.services.get('database').get(DB_WRITE, 'auth');
|
||||||
|
|
||||||
|
this.sessions = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
async authenticate_from_token (token) {
|
async authenticate_from_token (token) {
|
||||||
@ -43,6 +45,7 @@ class AuthService extends BaseService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ( ! decoded.hasOwnProperty('type') ) {
|
if ( ! decoded.hasOwnProperty('type') ) {
|
||||||
|
throw new Error('legacy token');
|
||||||
const user = await this.db.requireRead(
|
const user = await this.db.requireRead(
|
||||||
"SELECT * FROM `user` WHERE `uuid` = ? LIMIT 1",
|
"SELECT * FROM `user` WHERE `uuid` = ? LIMIT 1",
|
||||||
[decoded.uuid],
|
[decoded.uuid],
|
||||||
@ -66,6 +69,25 @@ class AuthService extends BaseService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( decoded.type === 'session' ) {
|
||||||
|
const session = this.get_session_(decoded.uuid);
|
||||||
|
|
||||||
|
if ( ! session ) {
|
||||||
|
throw APIError.create('token_auth_failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await get_user({ uuid: decoded.user_uid });
|
||||||
|
|
||||||
|
const actor_type = new UserActorType({
|
||||||
|
user,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Actor({
|
||||||
|
user_uid: decoded.user_uid,
|
||||||
|
type: actor_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ( decoded.type === 'app-under-user' ) {
|
if ( decoded.type === 'app-under-user' ) {
|
||||||
const user = await get_user({ uuid: decoded.user_uid });
|
const user = await get_user({ uuid: decoded.user_uid });
|
||||||
if ( ! user ) {
|
if ( ! user ) {
|
||||||
@ -149,6 +171,72 @@ class AuthService extends BaseService {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async create_session_ (user, meta = {}) {
|
||||||
|
this.log.info(`CREATING SESSION`);
|
||||||
|
const uuid = this.modules.uuidv4();
|
||||||
|
await this.db.write(
|
||||||
|
'INSERT INTO `sessions` ' +
|
||||||
|
'(`uuid`, `user_id`, `meta`) ' +
|
||||||
|
'VALUES (?, ?, ?)',
|
||||||
|
[uuid, user.id, JSON.stringify(meta)],
|
||||||
|
);
|
||||||
|
const session = { uuid, user_uid: user.uuid, meta };
|
||||||
|
this.sessions[uuid] = session;
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_session_ (uuid) {
|
||||||
|
this.log.info(`USING SESSION`);
|
||||||
|
if ( this.sessions[uuid] ) {
|
||||||
|
return this.sessions[uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [session] = await this.db.read(
|
||||||
|
"SELECT * FROM `sessions` WHERE `uuid` = ? LIMIT 1",
|
||||||
|
[uuid],
|
||||||
|
);
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create_session_token (user, meta) {
|
||||||
|
const session = await this.create_session_(user, meta);
|
||||||
|
|
||||||
|
const token = this.modules.jwt.sign({
|
||||||
|
type: 'session',
|
||||||
|
version: '0.0.0',
|
||||||
|
uuid: session.uuid,
|
||||||
|
meta: session.meta,
|
||||||
|
user_uid: user.uuid,
|
||||||
|
}, this.global_config.jwt_secret);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
async check_session (cur_token) {
|
||||||
|
const decoded = this.modules.jwt.verify(
|
||||||
|
cur_token, this.global_config.jwt_secret
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( decoded.type && decoded.type !== 'session' ) {
|
||||||
|
// throw APIError.create('token_auth_failed');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await get_user({ uuid: decoded.user_uid });
|
||||||
|
if ( ! user ) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( decoded.type ) return { user, token: cur_token };
|
||||||
|
|
||||||
|
this.log.info(`UPGRADING SESSION`);
|
||||||
|
|
||||||
|
// Upgrade legacy token
|
||||||
|
const token = await this.create_session_token(user);
|
||||||
|
return { user, token };
|
||||||
|
}
|
||||||
|
|
||||||
async create_access_token (authorizer, permissions) {
|
async create_access_token (authorizer, permissions) {
|
||||||
const jwt_obj = {};
|
const jwt_obj = {};
|
||||||
const authorizer_obj = {};
|
const authorizer_obj = {};
|
||||||
|
@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
|||||||
this.db = new Database(this.config.path);
|
this.db = new Database(this.config.path);
|
||||||
|
|
||||||
// Database upgrade logic
|
// Database upgrade logic
|
||||||
const TARGET_VERSION = 1;
|
const TARGET_VERSION = 2;
|
||||||
|
|
||||||
if ( do_setup ) {
|
if ( do_setup ) {
|
||||||
this.log.noticeme(`SETUP: creating database at ${this.config.path}`);
|
this.log.noticeme(`SETUP: creating database at ${this.config.path}`);
|
||||||
@ -50,6 +50,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
|||||||
'0001_create-tables.sql',
|
'0001_create-tables.sql',
|
||||||
'0002_add-default-apps.sql',
|
'0002_add-default-apps.sql',
|
||||||
'0003_user-permissions.sql',
|
'0003_user-permissions.sql',
|
||||||
|
'0004_sessions.sql',
|
||||||
].map(p => path_.join(__dirname, 'sqlite_setup', p));
|
].map(p => path_.join(__dirname, 'sqlite_setup', p));
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
for ( const filename of sql_files ) {
|
for ( const filename of sql_files ) {
|
||||||
@ -70,6 +71,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
|
|||||||
upgrade_files.push('0003_user-permissions.sql');
|
upgrade_files.push('0003_user-permissions.sql');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( user_version <= 1 ) {
|
||||||
|
upgrade_files.push('0004_sessions.sql');
|
||||||
|
}
|
||||||
|
|
||||||
if ( upgrade_files.length > 0 ) {
|
if ( upgrade_files.length > 0 ) {
|
||||||
this.log.noticeme(`Database out of date: ${this.config.path}`);
|
this.log.noticeme(`Database out of date: ${this.config.path}`);
|
||||||
this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`);
|
this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`);
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE `sessions` (
|
||||||
|
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"user_id" INTEGER NOT NULL,
|
||||||
|
"uuid" TEXT NOT NULL,
|
||||||
|
"meta" JSON DEFAULT NULL,
|
||||||
|
FOREIGN KEY("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user