mirror of
https://github.com/HeyPuter/puter.git
synced 2026-10-04 19:07:56 +00:00
[OIDC] allow user deletion for accounts without a password (#2567)
* fix: user deletion for OIDC accounts * clean(backend): update copied license header * clean(backend): replace previously removed comments * fix: double-encoding
This commit is contained in:
@@ -106,6 +106,8 @@ const hardcoded_user_group_permissions = {
|
||||
'local-terminal:access': {},
|
||||
},
|
||||
'b7220104-7905-4985-b996-649fdcdb3c8f': {
|
||||
'driver': {},
|
||||
'service': {},
|
||||
'service:hello-world:ii:hello-world': policy_perm('temp.es'),
|
||||
'service:puter-kvstore:ii:puter-kvstore': policy_perm('temp.kv'),
|
||||
'driver:puter-kvstore': policy_perm('temp.kv'),
|
||||
@@ -119,6 +121,8 @@ const hardcoded_user_group_permissions = {
|
||||
'service:es\\Csubdomain:ii:crud-q': policy_perm('user.es'),
|
||||
},
|
||||
'78b1b1dd-c959-44d2-b02c-8735671f9997': {
|
||||
'driver': {},
|
||||
'service': {},
|
||||
'service:hello-world:ii:hello-world': policy_perm('user.es'),
|
||||
'service:puter-kvstore:ii:puter-kvstore': policy_perm('user.kv'),
|
||||
'driver:puter-kvstore': policy_perm('user.kv'),
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
const eggspress = require('../../api/eggspress');
|
||||
const { deleteUser, invalidate_cached_user } = require('../../helpers');
|
||||
|
||||
const config = require('../../config');
|
||||
|
||||
module.exports = eggspress('/delete-own-user', {
|
||||
subdomain: 'api',
|
||||
auth: true,
|
||||
allowedMethods: ['POST'],
|
||||
}, async (req, res) => {
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
const validate_request = async () => {
|
||||
const user = req.user;
|
||||
|
||||
// `user` should always have a value, but this is checked
|
||||
// any way in case the auth middleware is broken.
|
||||
if ( ! user ) return false;
|
||||
|
||||
// temporary users don't require password verification
|
||||
if ( !user.email && !user.password ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! req.body.password ) return false;
|
||||
if ( !user || !user.password ) return false;
|
||||
if ( ! await bcrypt.compare(req.body.password, req.user.password) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if ( ! await validate_request() ) {
|
||||
return res.status(400).send({ success: false });
|
||||
}
|
||||
|
||||
res.clearCookie(config.cookie_name);
|
||||
|
||||
await deleteUser(req.user.id);
|
||||
invalidate_cached_user(req.user);
|
||||
|
||||
return res.send({ success: true });
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2026-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
const config = require('../../config');
|
||||
const { deleteUser, invalidate_cached_user } = require('../../helpers');
|
||||
|
||||
const REVALIDATION_COOKIE_NAME = 'puter_revalidation';
|
||||
|
||||
module.exports = {
|
||||
route: '/delete-own-user',
|
||||
methods: ['POST'],
|
||||
handler: async (req, res) => {
|
||||
res.clearCookie(config.cookie_name);
|
||||
res.clearCookie(REVALIDATION_COOKIE_NAME);
|
||||
|
||||
await deleteUser(req.user.id);
|
||||
invalidate_cached_user(req.user);
|
||||
|
||||
return res.send({ success: true });
|
||||
},
|
||||
};
|
||||
@@ -53,7 +53,6 @@ class PuterAPIService extends BaseService {
|
||||
app.use(require('../routers/auth/app-uid-from-origin'));
|
||||
app.use(require('../routers/auth/create-access-token'));
|
||||
app.use(require('../routers/auth/revoke-access-token'));
|
||||
app.use(require('../routers/auth/delete-own-user'));
|
||||
app.use(require('../routers/auth/configure-2fa'));
|
||||
app.use(require('../routers/drivers/call'));
|
||||
app.use(require('../routers/drivers/list-interfaces'));
|
||||
|
||||
@@ -109,9 +109,10 @@ class UserProtectedEndpointsService extends BaseService {
|
||||
next();
|
||||
});
|
||||
|
||||
// Do not allow temporary users
|
||||
// Do not allow temporary users (except for delete-own-user, which allows them)
|
||||
router.use(async (req, res, next) => {
|
||||
if ( req.method === 'OPTIONS' ) return next();
|
||||
if ( req.path === '/delete-own-user' ) return next();
|
||||
|
||||
if ( req.user.password === null && req.user.email === null ) {
|
||||
return APIError.create('temporary_account').write(res);
|
||||
@@ -122,6 +123,7 @@ class UserProtectedEndpointsService extends BaseService {
|
||||
/**
|
||||
* Middleware to validate identity: either password (bcrypt) or a valid OIDC revalidation cookie.
|
||||
* OIDC-only accounts (user.password === null) must use revalidation; password accounts may use either.
|
||||
* Temporary users (no password, no email) are allowed only for delete-own-user.
|
||||
*/
|
||||
router.use(async (req, res, next) => {
|
||||
if ( req.method === 'OPTIONS' ) return next();
|
||||
@@ -129,6 +131,10 @@ class UserProtectedEndpointsService extends BaseService {
|
||||
const user = await get_user({ id: req.user.id, force: true });
|
||||
const revalidationCookie = req.cookies && req.cookies[REVALIDATION_COOKIE_NAME];
|
||||
|
||||
if ( user.password === null && user.email === null ) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if ( req.body.password ) {
|
||||
if ( user.password === null ) {
|
||||
return (APIError.create('oidc_revalidation_required', null, await this.#revalidateUrlFields(req, user))).write(res);
|
||||
@@ -168,6 +174,8 @@ class UserProtectedEndpointsService extends BaseService {
|
||||
Endpoint(require('../../routers/user-protected/change-username.js')).attach(router);
|
||||
|
||||
Endpoint(require('../../routers/user-protected/disable-2fa.js')).attach(router);
|
||||
|
||||
Endpoint(require('../../routers/user-protected/delete-own-user.js')).attach(router);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user