';
- h += `${i18n('username')}`;
- h += `${html_encode(window.user.username)}`;
- h += '
';
- h += '
';
- h += ``;
+ h += '
';
+ h += '
';
+ h += '';
+ h += '
';
+ h += '
';
+ h += `${i18n('username')}`;
+ h += `${html_encode(window.user.username)}`;
+ h += '
';
+ h += '
';
+ h += ``;
h += '
';
// Password card (only for non-temp users)
- if ( !window.user.is_temp ) {
+ if ( ! window.user.is_temp ) {
h += '
';
- h += '
';
- h += '
';
- h += '';
- h += '
';
- h += '
';
- h += `${i18n('password')}`;
- h += '••••••••';
- h += '
';
- h += '
';
- h += ``;
+ h += '
';
+ h += '
';
+ h += '';
+ h += '
';
+ h += '
';
+ h += `${i18n('password')}`;
+ h += '••••••••';
+ h += '
';
+ h += '
';
+ h += ``;
h += '
';
}
// Email card (only if email exists)
if ( window.user.email ) {
h += '
';
- h += '
';
- h += '
';
- h += '';
- h += '
';
- h += '
';
- h += `${i18n('email')}`;
- h += `${html_encode(window.user.email)}`;
- h += '
';
- h += '
';
- h += ``;
+ h += '
';
+ h += '
';
+ h += '';
+ h += '
';
+ h += '
';
+ h += `${i18n('email')}`;
+ h += `${html_encode(window.user.email)}`;
+ h += '
';
+ h += '
';
+ h += ``;
h += '
';
}
+ // Auth token card
+ h += '
';
+ h += '
';
+ h += '
';
+ h += '';
+ h += '
';
+ h += '
';
+ h += `${i18n('auth_token')}`;
+ h += `${i18n('copy_token_description')}`;
+ h += '
';
+ h += '
';
+ h += ``;
+ h += '
';
+
// Danger zone
h += '
';
- h += '
';
- h += '
';
- h += '
';
- h += `${i18n('delete_account')}`;
- h += 'Permanently delete your account and all associated data. This action cannot be undone.';
- h += '
';
- h += '
';
- h += ``;
- h += '
';
+ h += '
';
+ h += '
';
+ h += '
';
+ h += `${i18n('delete_account')}`;
+ h += 'Permanently delete your account and all associated data. This action cannot be undone.';
+ h += '
';
+ h += '
';
+ h += ``;
+ h += '
';
h += '
';
h += '
'; // end settings-grid
@@ -156,6 +171,18 @@ const TabAccount = {
},
});
});
+ $el_window.find('.dashboard-section-account .copy-auth-token').on('click', function (e) {
+ UIWindowCopyToken({
+ show_header: true,
+ window_options: {
+ parent_uuid: $el_window.attr('data-element_uuid'),
+ backdrop: true,
+ close_on_backdrop_click: false,
+ parent_center: true,
+ stay_on_top: true,
+ },
+ });
+ });
$el_window.find('.dashboard-section-account .delete-account').on('click', function (e) {
UIWindowConfirmUserDeletion({
window_options: {
@@ -218,4 +245,3 @@ const TabAccount = {
};
export default TabAccount;
-
diff --git a/src/gui/src/UI/UIWindowCopyToken.js b/src/gui/src/UI/UIWindowCopyToken.js
new file mode 100644
index 000000000..5d5f0e616
--- /dev/null
+++ b/src/gui/src/UI/UIWindowCopyToken.js
@@ -0,0 +1,119 @@
+/**
+ * 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 .
+ */
+
+import UIWindow from './UIWindow.js';
+
+function UIWindowCopyToken (options = {}) {
+ return new Promise(async (resolve) => {
+ let h = '';
+
+ if ( options.show_header ) {
+ h += `
`;
+ h += `
`;
+ h += ``;
+ h += '
';
+ h += `
${i18n('auth_token')}
`;
+ h += `
${i18n('copy_token_message')}
`;
+ h += '
';
+ }
+
+ h += '
';
+ if ( ! options.show_header ) {
+ h += `
${i18n('copy_token_message')}
`;
+ }
+ h += `
`;
+ h += ``;
+ h += ``;
+ h += '
';
+ h += '
';
+ h += i18n('token_copied');
+ h += '
';
+ h += '
';
+
+ const el_window = await UIWindow({
+ title: i18n('auth_token'),
+ app: 'copy-token',
+ single_instance: true,
+ icon: null,
+ uid: null,
+ is_dir: false,
+ body_content: h,
+ has_head: !options.show_header,
+ selectable_body: false,
+ draggable_body: options.show_header,
+ allow_context_menu: false,
+ is_resizable: false,
+ is_droppable: false,
+ init_center: true,
+ allow_native_ctxmenu: false,
+ allow_user_select: false,
+ width: 450,
+ height: 'auto',
+ dominant: true,
+ show_in_taskbar: false,
+ window_class: 'window-publishWebsite',
+ body_css: {
+ width: 'initial',
+ height: '100%',
+ padding: '0',
+ 'background-color': 'rgb(245 247 249)',
+ 'backdrop-filter': 'blur(3px)',
+ },
+ ...options.window_options,
+ });
+
+ $(el_window).find('.copy-token-btn').on('click', function () {
+ const $btn = $(this);
+ navigator.clipboard.writeText(window.auth_token).then(() => {
+ $(el_window).find('.token-copied-msg').fadeIn();
+ $btn.text(i18n('token_copied'));
+ setTimeout(() => {
+ $(el_window).find('.token-copied-msg').fadeOut();
+ $btn.text(i18n('copy'));
+ }, 2000);
+ });
+ });
+
+ $(el_window).on('close', () => {
+ resolve();
+ });
+ });
+}
+
+def(UIWindowCopyToken, 'ui.window.UIWindowCopyToken');
+
+export default UIWindowCopyToken;
diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js
index 77bda3853..44784b9af 100644
--- a/src/gui/src/i18n/translations/en.js
+++ b/src/gui/src/i18n/translations/en.js
@@ -550,6 +550,14 @@ const en = {
'error_user_or_path_not_found': 'User or path not found.',
'error_invalid_username': 'Invalid username.',
+
+ // Auth token
+ auth_token: 'Auth Token',
+ token_copied: 'Token copied',
+ copy_auth_token: 'Copy Auth Token',
+ approve: 'Approve',
+ copy_token_message: 'Your authentication token is shown below. Keep it secret \u2014 anyone with this token can access your account.',
+ copy_token_description: 'View and copy your authentication token',
},
};
diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js
index 2b00779bb..2f4ed4eb6 100644
--- a/src/gui/src/initgui.js
+++ b/src/gui/src/initgui.js
@@ -30,6 +30,7 @@ import UIWindowRequestPermission from './UI/UIWindowRequestPermission.js';
import UIWindowSaveAccount from './UI/UIWindowSaveAccount.js';
import UIWindowSessionList from './UI/UIWindowSessionList.js';
import UIWindowSignup from './UI/UIWindowSignup.js';
+import UIWindowCopyToken from './UI/UIWindowCopyToken.js';
import { PROCESS_RUNNING } from './definitions.js';
import item_icon from './helpers/item_icon.js';
import update_last_touch_coordinates from './helpers/update_last_touch_coordinates.js';
@@ -623,7 +624,7 @@ window.initgui = async function (options) {
const approved = await UIAlert({
message: `Do you want to authorize and redirect to ${html_encode(redirectURL)}?`,
buttons: [
- { label: i18n('approve') || 'Approve', value: 'approve', type: 'primary' },
+ { label: i18n('approve'), value: 'approve', type: 'primary' },
{ label: i18n('cancel'), value: 'cancel', type: 'secondary' },
],
type: 'confirm',
@@ -637,6 +638,13 @@ window.initgui = async function (options) {
}
}
+ // -------------------------------------------------------------------------------------
+ // Action: CopyAuth — show dialog to copy auth token
+ // -------------------------------------------------------------------------------------
+ if ( action === 'copyauth' ) {
+ await UIWindowCopyToken({ show_header: true });
+ }
+
// -------------------------------------------------------------------------------------
// Load desktop, only if we're not embedded in a popup and not on the dashboard page
// -------------------------------------------------------------------------------------
@@ -968,15 +976,18 @@ window.initgui = async function (options) {
// Un-authed but not first visit -> try to log in/sign up
// -------------------------------------------------------------------------------------
if ( !window.is_auth() && (!window.first_visit_ever || window.disable_temp_users) ) {
+ const needs_action = action === 'authme' || action === 'copyauth';
+ const reload_on_success = !needs_action;
if ( window.logged_in_users.length > 0 ) {
- UIWindowSessionList();
+ await UIWindowSessionList({
+ reload_on_success,
+ });
}
else {
const resp = await fetch(`${window.gui_origin }/whoarewe`);
const whoarewe = await resp.json();
await UIWindowLogin({
- // show_signup_button:
- reload_on_success: true,
+ reload_on_success,
send_confirmation_code: false,
show_signup_button: ( !whoarewe.disable_user_signup ),
window_options: {
@@ -984,6 +995,9 @@ window.initgui = async function (options) {
},
});
}
+ if ( !reload_on_success && window.is_auth() ) {
+ document.dispatchEvent(new Event('login', { bubbles: true }));
+ }
}
// -------------------------------------------------------------------------------------
@@ -1153,7 +1167,7 @@ window.initgui = async function (options) {
const approved = await UIAlert({
message: `Do you want to authorize and redirect to ${html_encode(redirectURL)}?`,
buttons: [
- { label: i18n('approve') || 'Approve', value: 'approve', type: 'primary' },
+ { label: i18n('approve'), value: 'approve', type: 'primary' },
{ label: i18n('cancel'), value: 'cancel', type: 'secondary' },
],
type: 'confirm',
@@ -1167,6 +1181,13 @@ window.initgui = async function (options) {
}
}
+ // -------------------------------------------------------------------------------------
+ // Action: CopyAuth — show dialog to copy auth token
+ // -------------------------------------------------------------------------------------
+ if ( action === 'copyauth' ) {
+ await UIWindowCopyToken({ show_header: true });
+ }
+
// -------------------------------------------------------------------------------------
// Load desktop, if not embedded in a popup and not on the dashboard page
// -------------------------------------------------------------------------------------