look for a member's tea config where their home actually is

It read /home/<osUser>, which is not where an Officer member's home is. Theirs
is DATA_PATH/<email>/home — where provisionUserDirs puts it and what useradd
was given — so a member with a working tea login was told they had none, and
the settings page asked for a token they had already set.

osUserHome is the platform's own answer to that question, and the same one tea
itself gets when run as that account, so reading and running now agree about
the path.

Not a sudo problem: runAs was escalating correctly the whole time, into a
directory that does not exist on any install.
This commit is contained in:
officer
2026-08-19 12:27:58 +00:00
parent e820831aec
commit 7d79cab95c
+14 -3
View File
@@ -2,7 +2,7 @@ import { readFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
import { getUserById } from 'officerdb';
import { runAs } from '@@/os-user';
import { osUserHome, runAs } from '@@/os-user';
// Reading and writing `tea`'s own config, per user.
//
@@ -84,8 +84,18 @@ export async function osUserFor(userId: number): Promise<string | null> {
* The TOKEN ITSELF IS NOT RETURNED. Callers want to know whether one exists and who it belongs to; the
* value never needs to leave this file, and returning it would put it in a response body.
*/
/**
* A member's home is `DATA_PATH/<email>/home`, NOT `/home/<name>`.
*
* This said `/home/<osUser>` and therefore looked in a directory that does not exist on any Officer
* install — so a member with a working `tea` login was told they had none. `osUserHome` is the
* platform's own answer and the same one `provisionUserDirs` and `useradd` were given, so `tea` run as
* that account finds its config in exactly the place this now reads.
*/
async function rawConfig(userId: number): Promise<string | null> {
const osUser = await osUserFor(userId);
const user = await getUserById(userId);
const osUser = user?.osUser ?? null;
if (isOwnerUser(osUser)) {
try {
return readFileSync(configPathFor(homedir()), 'utf8');
@@ -93,7 +103,8 @@ async function rawConfig(userId: number): Promise<string | null> {
return null;
}
}
return asUser(osUser, ['cat', configPathFor(join('/home', osUser!))]);
if (!user?.email) return null;
return asUser(osUser, ['cat', configPathFor(osUserHome(user.email))]);
}
export async function readTeaLogin(userId: number, instanceUrl: string): Promise<TeaLogin | null> {