mirror of
https://github.com/HeyPuter/puter
synced 2024-11-15 06:15:47 +00:00
Add session manager ui
This commit is contained in:
parent
18b3e06fe8
commit
09bf422686
@ -90,7 +90,7 @@ router.post('/login', express.json(), body_parser_error_handler, async (req, res
|
||||
// check password
|
||||
if(await bcrypt.compare(req.body.password, user.password)){
|
||||
const svc_auth = req.services.get('auth');
|
||||
const token = await svc_auth.create_session_token(user);
|
||||
const token = await svc_auth.create_session_token(user, { req });
|
||||
//set cookie
|
||||
// res.cookie(config.cookie_name, token);
|
||||
res.cookie(config.cookie_name, token, {
|
||||
|
@ -247,7 +247,9 @@ module.exports = eggspress(['/signup'], {
|
||||
);
|
||||
|
||||
// create token for login
|
||||
const token = await svc_auth.create_session_token(user);
|
||||
const token = await svc_auth.create_session_token(user, {
|
||||
req,
|
||||
});
|
||||
// jwt.sign({uuid: user_uuid}, config.jwt_secret);
|
||||
|
||||
//-------------------------------------------------------------
|
||||
|
@ -174,6 +174,44 @@ class AuthService extends BaseService {
|
||||
|
||||
async create_session_ (user, meta = {}) {
|
||||
this.log.info(`CREATING SESSION`);
|
||||
|
||||
if ( meta.req ) {
|
||||
const req = meta.req;
|
||||
delete meta.req;
|
||||
|
||||
const ip = this.global_config.fowarded
|
||||
? req.headers['x-forwarded-for'] ||
|
||||
req.connection.remoteAddress
|
||||
: req.connection.remoteAddress
|
||||
;
|
||||
|
||||
meta.ip = ip;
|
||||
|
||||
meta.server = this.global_config.server_id;
|
||||
|
||||
if ( req.headers['user-agent'] ) {
|
||||
meta.user_agent = req.headers['user-agent'];
|
||||
}
|
||||
|
||||
if ( req.headers['referer'] ) {
|
||||
meta.referer = req.headers['referer'];
|
||||
}
|
||||
|
||||
if ( req.headers['origin'] ) {
|
||||
const origin = this._origin_from_url(req.headers['origin']);
|
||||
if ( origin ) {
|
||||
meta.origin = origin;
|
||||
}
|
||||
}
|
||||
|
||||
if ( req.headers['host'] ) {
|
||||
const host = this._origin_from_url(req.headers['host']);
|
||||
if ( host ) {
|
||||
meta.host = host;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uuid = this.modules.uuidv4();
|
||||
await this.db.write(
|
||||
'INSERT INTO `sessions` ' +
|
||||
@ -197,6 +235,8 @@ class AuthService extends BaseService {
|
||||
[uuid],
|
||||
);
|
||||
|
||||
session.meta = JSON.parse(session.meta ?? {});
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@ -214,7 +254,7 @@ class AuthService extends BaseService {
|
||||
return token;
|
||||
}
|
||||
|
||||
async check_session (cur_token) {
|
||||
async check_session (cur_token, meta) {
|
||||
const decoded = this.modules.jwt.verify(
|
||||
cur_token, this.global_config.jwt_secret
|
||||
);
|
||||
@ -245,7 +285,7 @@ class AuthService extends BaseService {
|
||||
|
||||
// Upgrade legacy token
|
||||
// TODO: phase this out
|
||||
const { token } = await this.create_session_token(user);
|
||||
const { token } = await this.create_session_token(user, meta);
|
||||
return { user, token };
|
||||
}
|
||||
|
||||
@ -318,6 +358,7 @@ class AuthService extends BaseService {
|
||||
if ( session.uuid === actor.type.session ) {
|
||||
session.current = true;
|
||||
}
|
||||
session.meta = JSON.parse(session.meta ?? {});
|
||||
});
|
||||
|
||||
return sessions;
|
||||
|
@ -26,6 +26,7 @@ import changeLanguage from "../../i18n/i18nChangeLanguage.js"
|
||||
import UIWindowConfirmUserDeletion from './UIWindowConfirmUserDeletion.js';
|
||||
import UITabAbout from './UITabAbout.js';
|
||||
import UIWindowThemeDialog from '../UIWindowThemeDialog.js';
|
||||
import UIWindowManageSessions from '../UIWindowManageSessions.js';
|
||||
|
||||
async function UIWindowSettings(options){
|
||||
return new Promise(async (resolve) => {
|
||||
@ -111,6 +112,14 @@ async function UIWindowSettings(options){
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
// session manager
|
||||
h += `<div class="settings-card">`;
|
||||
h += `<strong>${i18n('sessions')}</strong>`;
|
||||
h += `<div style="flex-grow:1;">`;
|
||||
h += `<button class="button manage-sessions" style="float:right;">${i18n('manage_sessions')}</button>`;
|
||||
h += `</div>`;
|
||||
h += `</div>`;
|
||||
|
||||
h += `</div>`;
|
||||
|
||||
// Personalization
|
||||
@ -324,6 +333,10 @@ async function UIWindowSettings(options){
|
||||
UIWindowThemeDialog();
|
||||
})
|
||||
|
||||
$(el_window).find('.manage-sessions').on('click', function (e) {
|
||||
UIWindowManageSessions();
|
||||
})
|
||||
|
||||
$(el_window).on('click', '.settings-sidebar-item', function(){
|
||||
const $this = $(this);
|
||||
const settings = $this.attr('data-settings');
|
||||
|
148
src/UI/UIWindowManageSessions.js
Normal file
148
src/UI/UIWindowManageSessions.js
Normal file
@ -0,0 +1,148 @@
|
||||
import UIAlert from "./UIAlert.js";
|
||||
import UIWindow from "./UIWindow.js";
|
||||
|
||||
const UIWindowManageSessions = async function UIWindowManageSessions () {
|
||||
const services = globalThis.services;
|
||||
|
||||
const w = await UIWindow({
|
||||
title: i18n('ui_manage_sessions'),
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
message: 'message',
|
||||
// body_icon: options.body_icon,
|
||||
// backdrop: options.backdrop ?? false,
|
||||
is_droppable: false,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
draggable_body: true,
|
||||
allow_context_menu: false,
|
||||
window_class: 'window-session-manager',
|
||||
dominant: true,
|
||||
body_content: '',
|
||||
// width: 600,
|
||||
// parent_uuid: options.parent_uuid,
|
||||
// ...options.window_options,
|
||||
});
|
||||
|
||||
const SessionWidget = ({ session }) => {
|
||||
const el = document.createElement('div');
|
||||
el.classList.add('session-widget');
|
||||
el.dataset.uuid = session.uuid;
|
||||
// '<pre>' +
|
||||
// JSON.stringify(session, null, 2) +
|
||||
// '</pre>';
|
||||
|
||||
const el_uuid = document.createElement('div');
|
||||
el_uuid.textContent = session.uuid;
|
||||
el.appendChild(el_uuid);
|
||||
el_uuid.classList.add('session-widget-uuid');
|
||||
|
||||
const el_meta = document.createElement('div');
|
||||
el_meta.classList.add('session-widget-meta');
|
||||
for ( const key in session.meta ) {
|
||||
const el_entry = document.createElement('div');
|
||||
el_entry.classList.add('session-widget-meta-entry');
|
||||
|
||||
const el_key = document.createElement('div');
|
||||
el_key.textContent = key;
|
||||
el_key.classList.add('session-widget-meta-key');
|
||||
el_entry.appendChild(el_key);
|
||||
|
||||
const el_value = document.createElement('div');
|
||||
el_value.textContent = session.meta[key];
|
||||
el_value.classList.add('session-widget-meta-value');
|
||||
el_entry.appendChild(el_value);
|
||||
|
||||
el_meta.appendChild(el_entry);
|
||||
}
|
||||
el.appendChild(el_meta);
|
||||
|
||||
const el_actions = document.createElement('div');
|
||||
el_actions.classList.add('session-widget-actions');
|
||||
|
||||
const el_btn_revoke = document.createElement('button');
|
||||
el_btn_revoke.textContent = i18n('ui_revoke');
|
||||
el_btn_revoke.classList.add('button', 'button-danger');
|
||||
el_btn_revoke.addEventListener('click', async () => {
|
||||
try{
|
||||
const alert_resp = await UIAlert({
|
||||
message: i18n('confirm_session_revoke'),
|
||||
buttons:[
|
||||
{
|
||||
label: i18n('yes'),
|
||||
value: 'yes',
|
||||
type: 'primary',
|
||||
},
|
||||
{
|
||||
label: i18n('cancel')
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
if ( alert_resp !== 'yes' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resp = await fetch(`${api_origin}/auth/revoke-session`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uuid: session.uuid,
|
||||
}),
|
||||
});
|
||||
if ( resp.ok ) {
|
||||
el.remove();
|
||||
return;
|
||||
}
|
||||
UIAlert({ message: await resp.text() }).appendTo(w_body);
|
||||
} catch ( e ) {
|
||||
UIAlert({ message: e.toString() }).appendTo(w_body);
|
||||
}
|
||||
});
|
||||
el_actions.appendChild(el_btn_revoke);
|
||||
el.appendChild(el_actions);
|
||||
|
||||
return {
|
||||
appendTo (parent) {
|
||||
parent.appendChild(el);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const reload_sessions = async () => {
|
||||
const resp = await fetch(`${api_origin}/auth/list-sessions`, {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
const sessions = await resp.json();
|
||||
|
||||
for ( const el of w_body.querySelectorAll('.session-widget') ) {
|
||||
if ( !sessions.find(s => s.uuid === el.dataset.uuid) ) {
|
||||
el.remove();
|
||||
}
|
||||
}
|
||||
|
||||
for ( const session of sessions ) {
|
||||
if ( w.querySelector(`.session-widget[data-uuid="${session.uuid}"]`) ) {
|
||||
continue;
|
||||
}
|
||||
SessionWidget({ session }).appendTo(w_body);
|
||||
}
|
||||
};
|
||||
|
||||
const w_body = w.querySelector('.window-body');
|
||||
|
||||
w_body.classList.add('session-manager-list');
|
||||
|
||||
reload_sessions();
|
||||
const interval = setInterval(reload_sessions, 8000);
|
||||
w.on_close = () => {
|
||||
clearInterval(interval);
|
||||
}
|
||||
};
|
||||
|
||||
export default UIWindowManageSessions;
|
@ -3703,3 +3703,61 @@ label {
|
||||
background: #04AA6D;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.session-manager-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.session-widget {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.session-widget-uuid {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #9c185b;
|
||||
}
|
||||
|
||||
.session-widget-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
max-height: 100px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.session-widget-meta-entry {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.session-widget-meta-key {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
flex-basis: 40%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.session-widget-meta-value {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.session-widget-actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
justify-content: flex-end;
|
||||
}
|
@ -51,6 +51,7 @@ const en = {
|
||||
confirm_new_password: "Confirm New Password",
|
||||
confirm_delete_user: "Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone.",
|
||||
confirm_delete_user_title: "Delete Account?",
|
||||
confirm_session_revoke: "Are you sure you want to revoke this session?",
|
||||
contact_us: "Contact Us",
|
||||
contain: 'Contain',
|
||||
continue: "Continue",
|
||||
@ -112,6 +113,7 @@ const en = {
|
||||
log_in: "Log In",
|
||||
log_into_another_account_anyway: 'Log into another account anyway',
|
||||
log_out: 'Log Out',
|
||||
manage_sessions: "Manage Sessions",
|
||||
move: 'Move',
|
||||
moving: "Moving",
|
||||
my_websites: "My Websites",
|
||||
@ -205,6 +207,8 @@ const en = {
|
||||
type: 'Type',
|
||||
type_confirm_to_delete_account: "Type 'confirm' to delete your account.",
|
||||
ui_colors: "UI Colors",
|
||||
ui_manage_sessions: "Session Manager",
|
||||
ui_revoke: "Revoke",
|
||||
undo: 'Undo',
|
||||
unlimited: 'Unlimited',
|
||||
unzip: "Unzip",
|
||||
|
Loading…
Reference in New Issue
Block a user