|
@@ -83,6 +83,17 @@ void registerKeyRoutes(ApiServer& s) {
|
|
|
}
|
|
}
|
|
|
scopePatch = std::optional<std::optional<KeyScope>>{ parseScope(body, effectiveAdmin) };
|
|
scopePatch = std::optional<std::optional<KeyScope>>{ parseScope(body, effectiveAdmin) };
|
|
|
}
|
|
}
|
|
|
|
|
+ // Invariant: a key cannot be both admin and scoped. parseScope already rejects
|
|
|
|
|
+ // sending a scope to an admin, but also catch promoting an already-scoped key to admin.
|
|
|
|
|
+ {
|
|
|
|
|
+ bool finalAdmin = false, finalScoped = false;
|
|
|
|
|
+ std::optional<ApiKey> cur;
|
|
|
|
|
+ for (const auto& k : d->keys.list()) if (k.id == id) { cur = k; break; }
|
|
|
|
|
+ finalAdmin = admin.has_value() ? *admin : (cur && cur->admin);
|
|
|
|
|
+ finalScoped = scopePatch.has_value() ? scopePatch->has_value() : (cur && cur->scope.has_value());
|
|
|
|
|
+ if (finalAdmin && finalScoped)
|
|
|
|
|
+ throw ApiError(ErrCode::Unprocessable, "validation", "a key cannot be both admin and scoped");
|
|
|
|
|
+ }
|
|
|
if (!d->keys.update(id, label, projects, admin, scopePatch))
|
|
if (!d->keys.update(id, label, projects, admin, scopePatch))
|
|
|
throw ApiError(ErrCode::NotFound, "not_found", "no such key");
|
|
throw ApiError(ErrCode::NotFound, "not_found", "no such key");
|
|
|
sendJson(res, 200, {{"updated", true}});
|
|
sendJson(res, 200, {{"updated", true}});
|