mirror of
https://github.com/tale/headplane.git
synced 2026-08-10 05:56:52 +00:00
fix: correctly handle user id passthrough on headscale actions
This commit is contained in:
@@ -65,12 +65,14 @@ export function makePreAuthKeyApi(
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Pre-0.28: expire takes user + key string.
|
||||
// Pre-0.28: expire takes the owning user's ID (a uint64 — Headscale
|
||||
// rejects names with `proto: invalid value for uint64 field user`)
|
||||
// plus the key string.
|
||||
await transport.request({
|
||||
method: "POST",
|
||||
path: "v1/preauthkey/expire",
|
||||
apiKey,
|
||||
body: { user: key.user?.name ?? "", key: key.key },
|
||||
body: { user: key.user?.id ?? "", key: key.key },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
+18
-41
@@ -77,13 +77,12 @@ export interface AuthService {
|
||||
|
||||
linkHeadscaleUser(userId: string, headscaleUserId: string): Promise<boolean>;
|
||||
unlinkHeadscaleUser(userId: string): Promise<void>;
|
||||
linkHeadscaleUserBySubject(subject: string, headscaleUserId: string): Promise<boolean>;
|
||||
listUsers(): Promise<HeadplaneUser[]>;
|
||||
claimedHeadscaleUserIds(): Promise<Set<string>>;
|
||||
roleForSubject(subject: string): Promise<Role | undefined>;
|
||||
roleForHeadscaleUser(headscaleUserId: string): Promise<Role | undefined>;
|
||||
transferOwnership(currentOwnerSubject: string, newOwnerSubject: string): Promise<boolean>;
|
||||
reassignSubject(subject: string, role: Role): Promise<boolean>;
|
||||
transferOwnership(currentOwnerUserId: string, newOwnerUserId: string): Promise<boolean>;
|
||||
reassignUser(userId: string, role: Role): Promise<boolean>;
|
||||
pruneExpiredSessions(): Promise<void>;
|
||||
start(): void;
|
||||
stop(): void;
|
||||
@@ -370,23 +369,6 @@ export function createAuthService(opts: AuthServiceOptions): AuthService {
|
||||
.where(eq(users.id, userId));
|
||||
}
|
||||
|
||||
async function linkHeadscaleUserBySubject(
|
||||
subject: string,
|
||||
headscaleUserId: string,
|
||||
): Promise<boolean> {
|
||||
const [user] = await opts.db
|
||||
.select({ id: users.id })
|
||||
.from(users)
|
||||
.where(eq(users.sub, subject))
|
||||
.limit(1);
|
||||
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return linkHeadscaleUser(user.id, headscaleUserId);
|
||||
}
|
||||
|
||||
async function listUsers(): Promise<HeadplaneUser[]> {
|
||||
return opts.db.select().from(users);
|
||||
}
|
||||
@@ -428,13 +410,17 @@ export function createAuthService(opts: AuthServiceOptions): AuthService {
|
||||
}
|
||||
|
||||
async function transferOwnership(
|
||||
currentOwnerSubject: string,
|
||||
newOwnerSubject: string,
|
||||
currentOwnerUserId: string,
|
||||
newOwnerUserId: string,
|
||||
): Promise<boolean> {
|
||||
if (currentOwnerUserId === newOwnerUserId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const [current] = await opts.db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.sub, currentOwnerSubject))
|
||||
.where(eq(users.id, currentOwnerUserId))
|
||||
.limit(1);
|
||||
|
||||
if (!current || current.role !== "owner") {
|
||||
@@ -444,10 +430,10 @@ export function createAuthService(opts: AuthServiceOptions): AuthService {
|
||||
const [target] = await opts.db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.sub, newOwnerSubject))
|
||||
.where(eq(users.id, newOwnerUserId))
|
||||
.limit(1);
|
||||
|
||||
if (!target || target.id === current.id) {
|
||||
if (!target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -464,24 +450,16 @@ export function createAuthService(opts: AuthServiceOptions): AuthService {
|
||||
return true;
|
||||
}
|
||||
|
||||
async function reassignSubject(subject: string, role: Role): Promise<boolean> {
|
||||
const currentRole = await roleForSubject(subject);
|
||||
if (currentRole === "owner") {
|
||||
async function reassignUser(userId: string, role: Role): Promise<boolean> {
|
||||
const [user] = await opts.db.select().from(users).where(eq(users.id, userId)).limit(1);
|
||||
if (!user || user.role === "owner") {
|
||||
return false;
|
||||
}
|
||||
|
||||
await opts.db
|
||||
.insert(users)
|
||||
.values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
role,
|
||||
caps: capsForRole(role),
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: users.sub,
|
||||
set: { role, caps: capsForRole(role), updated_at: new Date() },
|
||||
});
|
||||
.update(users)
|
||||
.set({ role, caps: capsForRole(role), updated_at: new Date() })
|
||||
.where(eq(users.id, userId));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -512,13 +490,12 @@ export function createAuthService(opts: AuthServiceOptions): AuthService {
|
||||
findOrCreateUser,
|
||||
linkHeadscaleUser,
|
||||
unlinkHeadscaleUser,
|
||||
linkHeadscaleUserBySubject,
|
||||
listUsers,
|
||||
claimedHeadscaleUserIds,
|
||||
roleForSubject,
|
||||
roleForHeadscaleUser,
|
||||
transferOwnership,
|
||||
reassignSubject,
|
||||
reassignUser,
|
||||
pruneExpiredSessions,
|
||||
start,
|
||||
stop,
|
||||
|
||||
Reference in New Issue
Block a user