ask for the URL first, and offer what tea already knows
The form asked for a URL and a token together, on a fresh instance, while the machine in front of it often had both on disk already — somebody had run `tea login` by hand. Two changes. One thing at a time: until the platform knows where Gitea is, a token cannot be checked, because there is nothing to check it against. So the owner names the instance first, and only then does the page ask for — or discover — a token. That step now probes /api/v1/version unauthenticated, since demanding a token to validate a URL refuses a good URL for the wrong reason and sends whoever typed it looking for a credential problem. And it reads tea's own config when the platform has no instance yet, offering the URL it finds. A machine that already has a working login should not be asked to retype what it can see. Members skip the first step entirely — the instance is the owner's.
This commit is contained in:
+36
-10
@@ -84,18 +84,20 @@ 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.
|
||||
*/
|
||||
export async function readTeaLogin(userId: number, instanceUrl: string): Promise<TeaLogin | null> {
|
||||
async function rawConfig(userId: number): Promise<string | null> {
|
||||
const osUser = await osUserFor(userId);
|
||||
const raw = isOwnerUser(osUser)
|
||||
? await (async () => {
|
||||
try {
|
||||
return readFileSync(configPathFor(homedir()), 'utf8');
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})()
|
||||
: await asUser(osUser, ['cat', configPathFor(join('/home', osUser!))]);
|
||||
if (isOwnerUser(osUser)) {
|
||||
try {
|
||||
return readFileSync(configPathFor(homedir()), 'utf8');
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return asUser(osUser, ['cat', configPathFor(join('/home', osUser!))]);
|
||||
}
|
||||
|
||||
export async function readTeaLogin(userId: number, instanceUrl: string): Promise<TeaLogin | null> {
|
||||
const raw = await rawConfig(userId);
|
||||
if (!raw) return null;
|
||||
|
||||
// One block per login. Matched loosely on purpose — the file is hand-editable and its key order is not
|
||||
@@ -115,6 +117,30 @@ export async function readTeaLogin(userId: number, instanceUrl: string): Promise
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whatever login `tea` already has, when the platform does not yet know the instance.
|
||||
*
|
||||
* A machine where somebody ran `tea login` by hand already knows the URL and holds a working token. Not
|
||||
* offering that back means asking them to retype something the box in front of them can see.
|
||||
*
|
||||
* Returns the FIRST login, which for a config with one is the only one, and for a config with several is
|
||||
* the one `tea` itself defaults to — the same answer the agent would get.
|
||||
*/
|
||||
export async function readAnyTeaLogin(userId: number): Promise<TeaLogin | null> {
|
||||
const raw = await rawConfig(userId);
|
||||
if (!raw) return null;
|
||||
const block = raw.split(/^\s*-\s+name:/m)[1];
|
||||
if (!block) return null;
|
||||
const url = block.match(/^\s*url:\s*(\S+)/m)?.[1]?.replace(/\/$/, '') ?? '';
|
||||
if (!url) return null;
|
||||
return {
|
||||
name: block.split('\n')[0]?.trim() ?? '',
|
||||
url,
|
||||
user: block.match(/^\s*user:\s*(\S+)/m)?.[1] ?? null,
|
||||
hasToken: /^\s*token:\s*\S+/m.test(block),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a login for this instance, as that user.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user