spongyicybulk commited on
Commit
278cbe8
·
verified ·
1 Parent(s): 19b7c4f

fix: clarify legacy api token recovery

Browse files
frontend/src/views/ApiTokensView.vue CHANGED
@@ -99,11 +99,38 @@
99
  </td>
100
  <td>{{ formatDateTime(token.lastUsedAt) }}</td>
101
  <td>{{ formatRestrictions(token.restrictions) }}</td>
102
- <td>{{ token.tokenPreview }}</td>
 
 
 
 
 
103
  <td>
104
  <div class="form-actions">
105
- <button class="btn btn-ghost" type="button" @click="copyTokenForRow(token)">复制 Token</button>
106
- <button class="btn btn-ghost" type="button" @click="rotateTokenForRow(token)">重新生成</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  <button class="btn btn-ghost" type="button" @click="editToken(token)">编辑</button>
108
  <button class="btn btn-ghost" type="button" @click="toggleToken(token)">
109
  {{ token.enabled ? '禁用' : '启用' }}
@@ -317,7 +344,9 @@ async function rotateTokenForRow(token) {
317
  error.value = '';
318
  message.value = '';
319
 
320
- const confirmed = window.confirm('是否重新生成这个 Token?旧 Token 会立刻失效。');
 
 
321
  if (!confirmed) return;
322
 
323
  try {
@@ -334,6 +363,9 @@ async function rotateTokenForRow(token) {
334
  latestToken.value = nextToken;
335
  latestTokenId.value = token.id;
336
  latestTokenReason.value = 'Token 已重新生成';
 
 
 
337
  message.value = 'API Token 已重新生成。旧 Token 已失效。';
338
  await loadTokens();
339
  } catch (err) {
 
99
  </td>
100
  <td>{{ formatDateTime(token.lastUsedAt) }}</td>
101
  <td>{{ formatRestrictions(token.restrictions) }}</td>
102
+ <td>
103
+ <div class="file-col">
104
+ <strong>{{ token.tokenPreview }}</strong>
105
+ <small v-if="!token.recoverable">旧 Token,原文不可恢复</small>
106
+ </div>
107
+ </td>
108
  <td>
109
  <div class="form-actions">
110
+ <button
111
+ v-if="token.recoverable"
112
+ class="btn btn-ghost"
113
+ type="button"
114
+ @click="copyTokenForRow(token)"
115
+ >
116
+ 复制 Token
117
+ </button>
118
+ <button
119
+ v-else
120
+ class="btn btn-ghost"
121
+ type="button"
122
+ @click="rotateTokenForRow(token)"
123
+ >
124
+ 重新生成并复制
125
+ </button>
126
+ <button
127
+ v-if="token.recoverable"
128
+ class="btn btn-ghost"
129
+ type="button"
130
+ @click="rotateTokenForRow(token)"
131
+ >
132
+ 重新生成
133
+ </button>
134
  <button class="btn btn-ghost" type="button" @click="editToken(token)">编辑</button>
135
  <button class="btn btn-ghost" type="button" @click="toggleToken(token)">
136
  {{ token.enabled ? '禁用' : '启用' }}
 
344
  error.value = '';
345
  message.value = '';
346
 
347
+ const confirmed = window.confirm(token.recoverable
348
+ ? '是否重新生成这个 Token?旧 Token 会立刻失效。'
349
+ : '这个旧 Token 无法恢复原文。是否立即重新生成并复制新的 Token?旧 Token 会立刻失效。');
350
  if (!confirmed) return;
351
 
352
  try {
 
363
  latestToken.value = nextToken;
364
  latestTokenId.value = token.id;
365
  latestTokenReason.value = 'Token 已重新生成';
366
+ if (!token.recoverable) {
367
+ await copy(nextToken, '新 Token 已复制。');
368
+ }
369
  message.value = 'API Token 已重新生成。旧 Token 已失效。';
370
  await loadTokens();
371
  } catch (err) {
server/lib/repos/api-token-repo.js CHANGED
@@ -58,11 +58,13 @@ function hashSecret(secret, salt) {
58
 
59
  function toPublicToken(row) {
60
  if (!row) return null;
 
61
  return {
62
  id: row.id,
63
  name: row.name,
64
  scopes: JSON.parse(row.scopes_json || '[]'),
65
  restrictions: JSON.parse(row.restrictions_json || '{}'),
 
66
  expiresAt: row.expires_at == null ? null : Number(row.expires_at),
67
  enabled: Boolean(row.enabled),
68
  createdAt: Number(row.created_at || 0),
 
58
 
59
  function toPublicToken(row) {
60
  if (!row) return null;
61
+ const encryptedSecret = String(row.encrypted_secret_json || '').trim();
62
  return {
63
  id: row.id,
64
  name: row.name,
65
  scopes: JSON.parse(row.scopes_json || '[]'),
66
  restrictions: JSON.parse(row.restrictions_json || '{}'),
67
+ recoverable: Boolean(encryptedSecret),
68
  expiresAt: row.expires_at == null ? null : Number(row.expires_at),
69
  enabled: Boolean(row.enabled),
70
  createdAt: Number(row.created_at || 0),