mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-02-17 15:01:42 +08:00
feat: add lastused field to api keys
This commit is contained in:
parent
34d953b337
commit
adf3bec630
@ -10,6 +10,6 @@ import org.springframework.stereotype.Repository;
|
||||
@RegisterConstructorMapper(ApiKey.class)
|
||||
public interface HangarApiKeysDAO {
|
||||
|
||||
@SqlQuery("SELECT created_at, name, token_identifier, raw_key_permissions::bigint permissions FROM api_keys WHERE owner_id = :userId ORDER BY created_at DESC")
|
||||
@SqlQuery("SELECT created_at, name, token_identifier, raw_key_permissions::bigint permissions, last_used FROM api_keys WHERE owner_id = :userId ORDER BY created_at DESC")
|
||||
List<ApiKey> getUserApiKeys(long userId);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import org.springframework.stereotype.Repository;
|
||||
public interface ApiKeyDAO {
|
||||
|
||||
@Timestamped
|
||||
@SqlUpdate("INSERT INTO api_keys (created_at, name, owner_id, token_identifier, token, raw_key_permissions) VALUES (:now, :name, :ownerId, :tokenIdentifier, :token, :permissions::bit(64))")
|
||||
@SqlUpdate("INSERT INTO api_keys (created_at, name, owner_id, token_identifier, token, raw_key_permissions, last_used) VALUES (:now, :name, :ownerId, :tokenIdentifier, :token, :permissions::bit(64), :now)")
|
||||
void insert(@BindBean ApiKeyTable apiKeyTable);
|
||||
|
||||
@SqlUpdate("DELETE FROM api_keys WHERE name = :keyName AND owner_id = :userId")
|
||||
@ -27,4 +27,7 @@ public interface ApiKeyDAO {
|
||||
|
||||
@SqlQuery("SELECT *, raw_key_permissions::bigint permissions FROM api_keys WHERE owner_id = :userId AND token_identifier = :identifier")
|
||||
ApiKeyTable findApiKey(long userId, String identifier);
|
||||
|
||||
@SqlUpdate("UPDATE api_keys SET last_used = :lastUsed WHERE id = :id")
|
||||
void update(@BindBean ApiKeyTable apiKeyTable);
|
||||
}
|
||||
|
@ -11,12 +11,14 @@ public class ApiKey extends Model {
|
||||
private final String name;
|
||||
private final String tokenIdentifier;
|
||||
private final List<NamedPermission> permissions;
|
||||
private final OffsetDateTime lastUsed;
|
||||
|
||||
public ApiKey(final OffsetDateTime createdAt, final String name, final String tokenIdentifier, final Permission permissions) {
|
||||
public ApiKey(final OffsetDateTime createdAt, final String name, final String tokenIdentifier, final Permission permissions, final OffsetDateTime lastUsed) {
|
||||
super(createdAt);
|
||||
this.name = name;
|
||||
this.tokenIdentifier = tokenIdentifier;
|
||||
this.permissions = permissions.toNamed();
|
||||
this.lastUsed = lastUsed;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -30,4 +32,8 @@ public class ApiKey extends Model {
|
||||
public List<NamedPermission> getPermissions() {
|
||||
return this.permissions;
|
||||
}
|
||||
|
||||
public OffsetDateTime getLastUsed() {
|
||||
return this.lastUsed;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ public class ApiKeyTable extends Table implements Named {
|
||||
private final String tokenIdentifier;
|
||||
private final String token;
|
||||
private final Permission permissions;
|
||||
private OffsetDateTime lastUsed = null;
|
||||
|
||||
public ApiKeyTable(final String name, final long ownerId, final String tokenIdentifier, final String token, final Permission permissions) {
|
||||
this.name = name;
|
||||
@ -23,13 +24,14 @@ public class ApiKeyTable extends Table implements Named {
|
||||
}
|
||||
|
||||
@JdbiConstructor
|
||||
public ApiKeyTable(final OffsetDateTime createdAt, final long id, final String name, final long ownerId, final String tokenIdentifier, final String token, final Permission permissions) {
|
||||
public ApiKeyTable(final OffsetDateTime createdAt, final long id, final String name, final long ownerId, final String tokenIdentifier, final String token, final Permission permissions, final OffsetDateTime lastUsed) {
|
||||
super(createdAt, id);
|
||||
this.name = name;
|
||||
this.ownerId = ownerId;
|
||||
this.tokenIdentifier = tokenIdentifier;
|
||||
this.token = token;
|
||||
this.permissions = permissions;
|
||||
this.lastUsed = lastUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,6 +55,14 @@ public class ApiKeyTable extends Table implements Named {
|
||||
return this.permissions;
|
||||
}
|
||||
|
||||
public OffsetDateTime getLastUsed() {
|
||||
return this.lastUsed;
|
||||
}
|
||||
|
||||
public void setLastUsed(final OffsetDateTime lastUsed) {
|
||||
this.lastUsed = lastUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApiKeyTable{" +
|
||||
@ -61,6 +71,7 @@ public class ApiKeyTable extends Table implements Named {
|
||||
", tokenIdentifier='" + this.tokenIdentifier + '\'' +
|
||||
", token='" + this.token + '\'' +
|
||||
", permissions=" + this.permissions +
|
||||
", lastUsed=" + this.lastUsed +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import io.papermc.hangar.model.db.auth.ApiKeyTable;
|
||||
import io.papermc.hangar.components.auth.service.TokenService;
|
||||
import io.papermc.hangar.util.CryptoUtils;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.OffsetDateTime;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -45,6 +46,8 @@ public class APIAuthenticationService extends HangarComponent {
|
||||
if (apiKeyTable == null) {
|
||||
throw new HangarApiException("No valid API Key found");
|
||||
}
|
||||
apiKeyTable.setLastUsed(OffsetDateTime.now());
|
||||
this.apiKeyDAO.update(apiKeyTable);
|
||||
|
||||
final UserTable userTable = this.userDAO.getUserTable(apiKeyTable.getOwnerId());
|
||||
final int aal = this.credentialsService.getAal(userTable);
|
||||
|
@ -0,0 +1,2 @@
|
||||
ALTER TABLE api_keys
|
||||
ADD COLUMN last_used timestamptz
|
@ -886,6 +886,7 @@
|
||||
"created": "Copy the created key before creating another one or refreshing the page. Do not share this with anyone else.",
|
||||
"keyIdentifier": "Identifier",
|
||||
"permissions": "Permissions",
|
||||
"lastUsed": "Last used",
|
||||
"permissionRequired": "At least one permission needs to be set.",
|
||||
"delete": "Delete",
|
||||
"copy": "Click to copy key to clipboard",
|
||||
|
@ -11,7 +11,6 @@ import { handleRequestError } from "~/composables/useErrorHandling";
|
||||
import InputCheckbox from "~/components/ui/InputCheckbox.vue";
|
||||
import Table from "~/components/design/Table.vue";
|
||||
import Alert from "~/components/design/Alert.vue";
|
||||
import Card from "~/components/design/Card.vue";
|
||||
import { useNotificationStore } from "~/store/notification";
|
||||
import { maxLength, minLength, required } from "~/composables/useValidationHelpers";
|
||||
import { validApiKeyName } from "~/composables/useHangarValidations";
|
||||
@ -20,6 +19,7 @@ import { NamedPermission } from "~/types/enums";
|
||||
import { definePageMeta } from "#imports";
|
||||
import Tooltip from "~/components/design/Tooltip.vue";
|
||||
import { useAuthStore } from "~/store/auth";
|
||||
import PrettyTime from "~/components/design/PrettyTime.vue";
|
||||
|
||||
definePageMeta({
|
||||
globalPermsRequired: ["EDIT_API_KEYS"],
|
||||
@ -131,6 +131,9 @@ function copy(event: any) {
|
||||
<th>
|
||||
{{ i18n.t("apiKeys.permissions") }}
|
||||
</th>
|
||||
<th class="min-w-100px">
|
||||
{{ i18n.t("apiKeys.lastUsed") }}
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
@ -139,6 +142,7 @@ function copy(event: any) {
|
||||
<td>{{ key.name }}</td>
|
||||
<td>{{ key.tokenIdentifier }}</td>
|
||||
<td>{{ key.permissions.join(", ") }}</td>
|
||||
<td><PrettyTime v-if="key.lastUsed" :time="key.lastUsed" long /></td>
|
||||
<td>
|
||||
<Button button-type="red" :loading="loadingDelete[key.name]" @click="deleteKey(key)"><IconMdiDelete /></Button>
|
||||
</td>
|
||||
|
2
frontend/src/types/api.d.ts
vendored
2
frontend/src/types/api.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { NamedPermission, Platform, ProjectCategory, Prompt, RoleCategory } from "~/types/enums";
|
||||
import { NamedPermission, Platform, ProjectCategory, Prompt } from "~/types/enums";
|
||||
import { Color, FlagReason, IPlatform, IProjectCategory, IPrompt, IVisibility } from "hangar-internal";
|
||||
import { IPermission, Role } from "hangar-api";
|
||||
|
||||
|
1
frontend/src/types/api/users.d.ts
vendored
1
frontend/src/types/api/users.d.ts
vendored
@ -31,5 +31,6 @@ declare module "hangar-api" {
|
||||
token?: string;
|
||||
tokenIdentifier?: string;
|
||||
permissions: NamedPermission[];
|
||||
lastUsed?: string;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user