dev: remove legacy whoami and use extension

This commit is contained in:
KernelDeimos
2025-09-24 15:43:47 -04:00
parent db5aef51b0
commit 353cf397cb
3 changed files with 2 additions and 267 deletions
+2 -2
View File
@@ -58,7 +58,7 @@ const whoami_common = ({ is_user, user }) => {
return details;
};
extension.get('/future/whoami', { subdomain: 'api' }, async (req, res, next) => {
extension.get('/whoami', { subdomain: 'api' }, async (req, res, next) => {
const actor = req.actor;
if ( ! actor ) {
throw Error('actor not found in context');
@@ -134,7 +134,7 @@ extension.get('/future/whoami', { subdomain: 'api' }, async (req, res, next) =>
res.send(details);
});
extension.post('/future/whoami', { subdomain: 'api' }, async (req, res) => {
extension.post('/whoami', { subdomain: 'api' }, async (req, res) => {
const actor = req.actor;
if ( ! actor ) {
throw Error('actor not found in context');
-264
View File
@@ -1,264 +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/>.
*/
"use strict"
const express = require('express');
// Timeago is so inconvenient to instantiate that I'm using an IIFE
// to reduce the impact on the scope.
const timeago = (() => {
const TimeAgo = require('javascript-time-ago');
TimeAgo.addDefaultLocale(require('javascript-time-ago/locale/en'));
return new TimeAgo('en-US');
})();
const { get_taskbar_items, is_shared_with_anyone, suggest_app_for_fsentry, get_app, get_descendants, id2uuid } = require('../helpers');
const auth = require('../middleware/auth.js');
const _path = require('path');
const eggspress = require('../api/eggspress');
const { Context } = require('../util/context');
const { UserActorType, AppUnderUserActorType } = require('../services/auth/Actor');
const whoami_common = ({ is_user, user }) => {
const details = {};
// User's immutable default (often called "system") directories'
// alternative (to path) identifiers are sent to the user's client
// (but not to apps; they don't need this information)
if ( is_user ) {
const directories = details.directories = {};
const name_to_path = {
'desktop_uuid': `/${user.username}/Desktop`,
'appdata_uuid': `/${user.username}/AppData`,
'documents_uuid': `/${user.username}/Documents`,
'pictures_uuid': `/${user.username}/Pictures`,
'videos_uuid': `/${user.username}/Videos`,
'trash_uuid': `/${user.username}/Trash`,
};
for ( const k in name_to_path ) {
directories[name_to_path[k]] = user[k];
}
}
if(user.last_activity_ts){
// Create a Date object and get the epoch timestamp
let epoch;
try{
epoch = new Date(user.last_activity_ts).getTime();
// round to 1 decimal place
epoch = Math.round(epoch/1000);
}catch(e){
// console.error('Error parsing last_activity_ts', e);
}
// add last_activity_ts
details.last_activity_ts = epoch;
}
return details;
};
// -----------------------------------------------------------------------//
// GET /whoami
// -----------------------------------------------------------------------//
const WHOAMI_GET = eggspress('/whoami', {
subdomain: 'api',
auth2: true,
allowedMethods: ['GET'],
}, async (req, res, next) => {
const actor = Context.get('actor');
if ( ! actor ) {
throw Error('actor not found in context');
}
const is_user = actor.type instanceof UserActorType;
if ( req.query.icon_size ) {
const ALLOWED_SIZES = ['16', '32', '64', '128', '256', '512'];
if ( ! ALLOWED_SIZES.includes(req.query.icon_size) ) {
res.status(400).send({ error: 'Invalid icon_size' });
}
}
// send user object
const details = {
username: req.user.username,
uuid: req.user.uuid,
email: req.user.email,
unconfirmed_email: req.user.email,
email_confirmed: req.user.email_confirmed
|| req.user.username === 'admin',
requires_email_confirmation: req.user.requires_email_confirmation,
desktop_bg_url: req.user.desktop_bg_url,
desktop_bg_color: req.user.desktop_bg_color,
desktop_bg_fit: req.user.desktop_bg_fit,
is_temp: (req.user.password === null && req.user.email === null),
taskbar_items: await get_taskbar_items(req.user, {
...(req.query.icon_size
? { icon_size: req.query.icon_size }
: { no_icons: true }),
}),
referral_code: req.user.referral_code,
otp: !! req.user.otp_enabled,
human_readable_age: timeago.format(
new Date(req.user.timestamp)),
...(req.new_token ? { token: req.token } : {})
};
// TODO: redundant? GetUserService already puts these values on 'user'
// Get whoami values from other services
const svc_whoami = req.services.get('whoami');
const provider_details = await svc_whoami.get_details({
user: req.user,
actor: actor,
});
Object.assign(details, provider_details);
if ( ! is_user ) {
// When apps call /whoami they should not see these attributes
// delete details.username;
// delete details.uuid;
delete details.email;
delete details.unconfirmed_email;
delete details.desktop_bg_url;
delete details.desktop_bg_color;
delete details.desktop_bg_fit;
delete details.taskbar_items;
delete details.token;
delete details.human_readable_age;
}
if ( actor.type instanceof AppUnderUserActorType ) {
details.app_name = actor.type.app.name;
// IDEA: maybe we do this in the future
// details.app = {
// name: actor.type.app.name,
// };
}
Object.assign(details, whoami_common({ is_user, user: req.user }));
res.send(details);
})
// -----------------------------------------------------------------------//
// POST /whoami
// -----------------------------------------------------------------------//
const WHOAMI_POST = new express.Router();
WHOAMI_POST.post('/whoami', auth, express.json(), async (req, response, next)=>{
// check subdomain
if(require('../helpers').subdomain(req) !== 'api') {
return;
}
const actor = Context.get('actor');
if ( ! actor ) {
throw Error('actor not found in context');
}
const is_user = actor.type instanceof UserActorType;
if ( ! is_user ) {
throw Error('actor is not a user');
}
let desktop_items = [];
// check if user asked for desktop items
if(req.query.return_desktop_items === 1 || req.query.return_desktop_items === '1' || req.query.return_desktop_items === 'true'){
// by cached desktop id
if(req.user.desktop_id){
// TODO: Check if used anywhere, maybe remove
// eslint-disable-next-line no-undef
desktop_items = await db.read(
`SELECT * FROM fsentries
WHERE user_id = ? AND parent_uid = ?`,
[req.user.id, await id2uuid(req.user.desktop_id)]
)
}
// by desktop path
else{
desktop_items = await get_descendants(req.user.username +'/Desktop', req.user, 1, true);
}
// clean up desktop items and add some extra information
if(desktop_items.length > 0){
if(desktop_items.length > 0){
for (let i = 0; i < desktop_items.length; i++) {
if(desktop_items[i].id !== null){
// suggested_apps for files
if(!desktop_items[i].is_dir){
desktop_items[i].suggested_apps = await suggest_app_for_fsentry(desktop_items[i], {user: req.user});
}
// is_shared
desktop_items[i].is_shared = await is_shared_with_anyone(desktop_items[i].id);
// associated_app
if(desktop_items[i].associated_app_id){
const app = await get_app({id: desktop_items[i].associated_app_id})
// remove some privileged information
delete app.id;
delete app.approved_for_listing;
delete app.approved_for_opening_items;
delete app.godmode;
delete app.owner_user_id;
// add to array
desktop_items[i].associated_app = app;
}else{
desktop_items[i].associated_app = {};
}
// remove associated_app_id since it's sensitive info
// delete desktop_items[i].associated_app_id;
}
// id is sesitive info
delete desktop_items[i].id;
delete desktop_items[i].user_id;
delete desktop_items[i].bucket;
desktop_items[i].path = _path.join('/', req.user.username, desktop_items[i].name)
}
}
}
}
// send user object
response.send(Object.assign({
username: req.user.username,
uuid: req.user.uuid,
email: req.user.email,
email_confirmed: req.user.email_confirmed
|| req.user.username === 'admin',
requires_email_confirmation: req.user.requires_email_confirmation,
desktop_bg_url: req.user.desktop_bg_url,
desktop_bg_color: req.user.desktop_bg_color,
desktop_bg_fit: req.user.desktop_bg_fit,
is_temp: (req.user.password === null && req.user.email === null),
taskbar_items: await get_taskbar_items(req.user),
desktop_items: desktop_items,
referral_code: req.user.referral_code,
}, whoami_common({ is_user, user: req.user })));
});
module.exports = app => {
app.use(WHOAMI_GET);
app.use(WHOAMI_POST);
};
@@ -91,7 +91,6 @@ class PuterAPIService extends BaseService {
app.use(require('../routers/healthcheck'))
app.use(require('../routers/test'))
app.use(require('../routers/update-taskbar-items'))
require('../routers/whoami')(app);
Endpoint({