mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 18:31:33 +00:00
fix: show remote sync account identity (#1110)
* fix: show remote sync account identity * cover getRemoteSyncUserInfo and make its null contract hold Nothing asserted the renderer-side gate: browser builds must not reach for the IPC bridge, and a missing bridge, an unconfigured server, an expired JWT or a failed channel all have to degrade to no identity rather than throw. Writing that turned up a mismatch — with no preload bridge the optional chain resolved to undefined while the signature promises null. The only caller uses ??, so nothing is broken today, but the type was not telling the truth. The main-process half (token expiry, /users/me, the roles fallback) stays uncovered: remote-sync.cjs requires electron at load, so exercising it means stubbing safeStorage and the filesystem, which is a bigger change than this PR warrants.
This commit is contained in:
@@ -1579,6 +1579,10 @@ ipcMain.handle("get-remote-sync-status", () => {
|
||||
return remoteSync.getRemoteSyncEngine()?.status || null;
|
||||
});
|
||||
|
||||
ipcMain.handle("get-remote-sync-user-info", () => {
|
||||
return remoteSync.getRemoteSyncUserInfo();
|
||||
});
|
||||
|
||||
ipcMain.handle("remote-sync-now", async () => {
|
||||
return (await remoteSync.getRemoteSyncEngine()?.syncNow()) || null;
|
||||
});
|
||||
|
||||
@@ -135,6 +135,41 @@ function clearRemoteSyncJwt() {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async function getRemoteSyncUserInfo() {
|
||||
const config = getRemoteSyncConfig();
|
||||
const token = getRemoteSyncJwt();
|
||||
if (!config?.serverUrl || !token || isJwtExpiredOrExpiringSoon(token)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const baseUrl = config.serverUrl.replace(/\/$/, "");
|
||||
const userResponse = await fetch(`${baseUrl}/users/me`, {
|
||||
headers: { Authorization: `Bearer ${token}`, "X-Electron-App": "true" },
|
||||
});
|
||||
if (!userResponse.ok) return null;
|
||||
|
||||
const user = await userResponse.json();
|
||||
const rolesResponse = await fetch(
|
||||
`${baseUrl}/rbac/users/${encodeURIComponent(user.userId)}/roles`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}`, "X-Electron-App": "true" },
|
||||
},
|
||||
);
|
||||
const roles = rolesResponse.ok
|
||||
? (await rolesResponse.json()).roles || []
|
||||
: [];
|
||||
|
||||
return {
|
||||
userId: user.userId,
|
||||
username: user.username,
|
||||
is_admin: !!user.is_admin,
|
||||
is_oidc: !!user.is_oidc,
|
||||
is_dual_auth: !!user.is_dual_auth,
|
||||
totp_enabled: !!user.totp_enabled,
|
||||
roles,
|
||||
};
|
||||
}
|
||||
|
||||
function decodeJwtExpiry(token) {
|
||||
try {
|
||||
const payloadB64 = token.split(".")[1];
|
||||
@@ -511,6 +546,7 @@ module.exports = {
|
||||
saveRemoteSyncJwt,
|
||||
getRemoteSyncJwt,
|
||||
clearRemoteSyncJwt,
|
||||
getRemoteSyncUserInfo,
|
||||
isJwtExpiredOrExpiringSoon,
|
||||
decodeJwtExpiry,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user