mirror of
https://github.com/HeyPuter/puter
synced 2024-11-15 06:15:47 +00:00
Add session listing and revocation
This commit is contained in:
parent
e436693d3e
commit
18b3e06fe8
@ -0,0 +1,23 @@
|
|||||||
|
const eggspress = require("../../api/eggspress");
|
||||||
|
const { UserActorType } = require("../../services/auth/Actor");
|
||||||
|
const { Context } = require("../../util/context");
|
||||||
|
|
||||||
|
module.exports = eggspress('/auth/list-sessions', {
|
||||||
|
subdomain: 'api',
|
||||||
|
auth2: true,
|
||||||
|
allowedMethods: ['GET'],
|
||||||
|
}, async (req, res, next) => {
|
||||||
|
const x = Context.get();
|
||||||
|
const svc_auth = x.get('services').get('auth');
|
||||||
|
|
||||||
|
// Only users can list their own sessions
|
||||||
|
// apps, access tokens, etc should NEVER access this
|
||||||
|
const actor = x.get('actor');
|
||||||
|
if ( ! (actor.type instanceof UserActorType) ) {
|
||||||
|
throw APIError.create('forbidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessions = await svc_auth.list_sessions(actor);
|
||||||
|
|
||||||
|
res.json(sessions);
|
||||||
|
});
|
33
packages/backend/src/routers/auth/revoke-session.js
Normal file
33
packages/backend/src/routers/auth/revoke-session.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
const APIError = require("../../api/APIError");
|
||||||
|
const eggspress = require("../../api/eggspress");
|
||||||
|
const { UserActorType } = require("../../services/auth/Actor");
|
||||||
|
const { Context } = require("../../util/context");
|
||||||
|
|
||||||
|
module.exports = eggspress('/auth/revoke-session', {
|
||||||
|
subdomain: 'api',
|
||||||
|
auth2: true,
|
||||||
|
allowedMethods: ['POST'],
|
||||||
|
}, async (req, res, next) => {
|
||||||
|
const x = Context.get();
|
||||||
|
const svc_auth = x.get('services').get('auth');
|
||||||
|
|
||||||
|
// Only users can list their own sessions
|
||||||
|
// apps, access tokens, etc should NEVER access this
|
||||||
|
const actor = x.get('actor');
|
||||||
|
if ( ! (actor.type instanceof UserActorType) ) {
|
||||||
|
throw APIError.create('forbidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure valid UUID
|
||||||
|
if ( ! req.body.uuid || typeof req.body.uuid !== 'string' ) {
|
||||||
|
throw APIError.create('field_invalid', null, {
|
||||||
|
key: 'uuid',
|
||||||
|
expected: 'string'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessions = await svc_auth.revoke_session(
|
||||||
|
actor, req.body.uuid);
|
||||||
|
|
||||||
|
res.json({ sessions });
|
||||||
|
});
|
@ -89,7 +89,8 @@ router.post('/login', express.json(), body_parser_error_handler, async (req, res
|
|||||||
return res.status(400).send('Incorrect password.')
|
return res.status(400).send('Incorrect password.')
|
||||||
// check password
|
// check password
|
||||||
if(await bcrypt.compare(req.body.password, user.password)){
|
if(await bcrypt.compare(req.body.password, user.password)){
|
||||||
const token = await jwt.sign({uuid: user.uuid}, config.jwt_secret)
|
const svc_auth = req.services.get('auth');
|
||||||
|
const token = await svc_auth.create_session_token(user);
|
||||||
//set cookie
|
//set cookie
|
||||||
// res.cookie(config.cookie_name, token);
|
// res.cookie(config.cookie_name, token);
|
||||||
res.cookie(config.cookie_name, token, {
|
res.cookie(config.cookie_name, token, {
|
||||||
|
@ -52,6 +52,7 @@ module.exports = eggspress(['/signup'], {
|
|||||||
const validator = require('validator')
|
const validator = require('validator')
|
||||||
let uuid_user;
|
let uuid_user;
|
||||||
|
|
||||||
|
const svc_auth = Context.get('services').get('auth');
|
||||||
const svc_authAudit = Context.get('services').get('auth-audit');
|
const svc_authAudit = Context.get('services').get('auth-audit');
|
||||||
svc_authAudit.record({
|
svc_authAudit.record({
|
||||||
requester: Context.get('requester'),
|
requester: Context.get('requester'),
|
||||||
@ -67,9 +68,11 @@ module.exports = eggspress(['/signup'], {
|
|||||||
|
|
||||||
// check if user is already logged in
|
// check if user is already logged in
|
||||||
if ( req.body.is_temp && req.cookies[config.cookie_name] ) {
|
if ( req.body.is_temp && req.cookies[config.cookie_name] ) {
|
||||||
const token = req.cookies[config.cookie_name];
|
const { user, token } = await svc_auth.check_session(
|
||||||
const decoded = await jwt.verify(token, config.jwt_secret);
|
req.cookies[config.cookie_name]
|
||||||
const user = await get_user({ uuid: decoded.uuid });
|
);
|
||||||
|
// const decoded = await jwt.verify(token, config.jwt_secret);
|
||||||
|
// const user = await get_user({ uuid: decoded.uuid });
|
||||||
if ( user ) {
|
if ( user ) {
|
||||||
return res.send({
|
return res.send({
|
||||||
token: token,
|
token: token,
|
||||||
@ -233,17 +236,20 @@ module.exports = eggspress(['/signup'], {
|
|||||||
db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]);
|
db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]);
|
||||||
invalidate_cached_user_by_id(pseudo_user.id);
|
invalidate_cached_user_by_id(pseudo_user.id);
|
||||||
}
|
}
|
||||||
// create token for login
|
|
||||||
const token = await jwt.sign({uuid: user_uuid}, config.jwt_secret);
|
|
||||||
|
|
||||||
// user id
|
// user id
|
||||||
// todo if pseudo user, assign directly no need to do another DB lookup
|
// todo if pseudo user, assign directly no need to do another DB lookup
|
||||||
const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id;
|
const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id;
|
||||||
|
|
||||||
const [user] = await db.read(
|
const [user] = await db.read(
|
||||||
'SELECT * FROM `user` WHERE `id` = ? LIMIT 1',
|
'SELECT * FROM `user` WHERE `id` = ? LIMIT 1',
|
||||||
[user_id]
|
[user_id]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// create token for login
|
||||||
|
const token = await svc_auth.create_session_token(user);
|
||||||
|
// jwt.sign({uuid: user_uuid}, config.jwt_secret);
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
// email confirmation
|
// email confirmation
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
|
@ -33,6 +33,8 @@ class PuterAPIService extends BaseService {
|
|||||||
app.use(require('../routers/auth/grant-user-user'));
|
app.use(require('../routers/auth/grant-user-user'));
|
||||||
app.use(require('../routers/auth/revoke-user-user'));
|
app.use(require('../routers/auth/revoke-user-user'));
|
||||||
app.use(require('../routers/auth/list-permissions'))
|
app.use(require('../routers/auth/list-permissions'))
|
||||||
|
app.use(require('../routers/auth/list-sessions'))
|
||||||
|
app.use(require('../routers/auth/revoke-session'))
|
||||||
app.use(require('../routers/auth/check-app'))
|
app.use(require('../routers/auth/check-app'))
|
||||||
app.use(require('../routers/auth/app-uid-from-origin'))
|
app.use(require('../routers/auth/app-uid-from-origin'))
|
||||||
app.use(require('../routers/auth/create-access-token'))
|
app.use(require('../routers/auth/create-access-token'))
|
||||||
|
@ -70,7 +70,7 @@ class AuthService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( decoded.type === 'session' ) {
|
if ( decoded.type === 'session' ) {
|
||||||
const session = this.get_session_(decoded.uuid);
|
const session = await this.get_session_(decoded.uuid);
|
||||||
|
|
||||||
if ( ! session ) {
|
if ( ! session ) {
|
||||||
throw APIError.create('token_auth_failed');
|
throw APIError.create('token_auth_failed');
|
||||||
@ -80,6 +80,7 @@ class AuthService extends BaseService {
|
|||||||
|
|
||||||
const actor_type = new UserActorType({
|
const actor_type = new UserActorType({
|
||||||
user,
|
user,
|
||||||
|
session: session.uuid,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Actor({
|
return new Actor({
|
||||||
@ -218,8 +219,9 @@ class AuthService extends BaseService {
|
|||||||
cur_token, this.global_config.jwt_secret
|
cur_token, this.global_config.jwt_secret
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('\x1B[36;1mDECODED SESSION', decoded);
|
||||||
|
|
||||||
if ( decoded.type && decoded.type !== 'session' ) {
|
if ( decoded.type && decoded.type !== 'session' ) {
|
||||||
// throw APIError.create('token_auth_failed');
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,12 +230,22 @@ class AuthService extends BaseService {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( decoded.type ) return { user, token: cur_token };
|
if ( decoded.type ) {
|
||||||
|
// Ensure session exists
|
||||||
|
const session = await this.get_session_(decoded.uuid);
|
||||||
|
if ( ! session ) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the session
|
||||||
|
return { user, token: cur_token };
|
||||||
|
}
|
||||||
|
|
||||||
this.log.info(`UPGRADING SESSION`);
|
this.log.info(`UPGRADING SESSION`);
|
||||||
|
|
||||||
// Upgrade legacy token
|
// Upgrade legacy token
|
||||||
const token = await this.create_session_token(user);
|
// TODO: phase this out
|
||||||
|
const { token } = await this.create_session_token(user);
|
||||||
return { user, token };
|
return { user, token };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,6 +306,31 @@ class AuthService extends BaseService {
|
|||||||
return jwt;
|
return jwt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async list_sessions (actor) {
|
||||||
|
// We won't take the cached sessions here because it's
|
||||||
|
// possible the user has sessions on other servers
|
||||||
|
const sessions = await this.db.read(
|
||||||
|
'SELECT uuid, meta FROM `sessions` WHERE `user_id` = ?',
|
||||||
|
[actor.type.user.id],
|
||||||
|
);
|
||||||
|
|
||||||
|
sessions.forEach(session => {
|
||||||
|
if ( session.uuid === actor.type.session ) {
|
||||||
|
session.current = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
async revoke_session (actor, uuid) {
|
||||||
|
delete this.sessions[uuid];
|
||||||
|
await this.db.write(
|
||||||
|
`DELETE FROM sessions WHERE uuid = ? AND user_id = ?`,
|
||||||
|
[uuid, actor.type.user.id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async get_user_app_token_from_origin (origin) {
|
async get_user_app_token_from_origin (origin) {
|
||||||
origin = this._origin_from_url(origin);
|
origin = this._origin_from_url(origin);
|
||||||
const app_uid = await this._app_uid_from_origin(origin);
|
const app_uid = await this._app_uid_from_origin(origin);
|
||||||
|
Loading…
Reference in New Issue
Block a user