mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-22 21:50:13 +00:00
Improve Bitwarden compatibility across account, sync, attachment, and send flows
This commit is contained in:
@@ -500,7 +500,6 @@ export function createAuthedFetch(getSession: () => SessionState | null, setSess
|
||||
if (!session?.accessToken) throw new Error(t('txt_offline_vault_readonly'));
|
||||
const headers = new Headers(init.headers || {});
|
||||
headers.set('Authorization', `Bearer ${session.accessToken}`);
|
||||
headers.set('X-NodeWarden-Web', '1');
|
||||
|
||||
let resp = await retryableRequest(headers);
|
||||
if (resp.status !== 401 || (!session.refreshToken && session.authMode !== 'web-cookie')) return resp;
|
||||
@@ -509,7 +508,6 @@ export function createAuthedFetch(getSession: () => SessionState | null, setSess
|
||||
if (latest?.accessToken && latest.accessToken !== session.accessToken) {
|
||||
const latestHeaders = new Headers(init.headers || {});
|
||||
latestHeaders.set('Authorization', `Bearer ${latest.accessToken}`);
|
||||
latestHeaders.set('X-NodeWarden-Web', '1');
|
||||
resp = await retryableRequest(latestHeaders);
|
||||
if (resp.status !== 401) return resp;
|
||||
}
|
||||
@@ -535,7 +533,6 @@ export function createAuthedFetch(getSession: () => SessionState | null, setSess
|
||||
|
||||
const retryHeaders = new Headers(init.headers || {});
|
||||
retryHeaders.set('Authorization', `Bearer ${nextSession.accessToken}`);
|
||||
retryHeaders.set('X-NodeWarden-Web', '1');
|
||||
resp = await retryableRequest(retryHeaders);
|
||||
return resp;
|
||||
};
|
||||
@@ -599,14 +596,35 @@ export async function changeMasterPassword(
|
||||
const nextEnc = await hkdfExpand(nextMasterKey, 'enc', 32);
|
||||
const nextMac = await hkdfExpand(nextMasterKey, 'mac', 32);
|
||||
const newKey = await encryptBw(userSym.slice(0, 64), nextEnc, nextMac);
|
||||
const newMasterPasswordHash = bytesToBase64(nextHash);
|
||||
|
||||
const resp = await authedFetch('/api/accounts/password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
currentPasswordHash: current.hash,
|
||||
newMasterPasswordHash: bytesToBase64(nextHash),
|
||||
newKey,
|
||||
masterPasswordHash: current.hash,
|
||||
newMasterPasswordHash,
|
||||
key: newKey,
|
||||
authenticationData: {
|
||||
kdf: {
|
||||
kdfType: 0,
|
||||
iterations: current.kdfIterations,
|
||||
memory: null,
|
||||
parallelism: null,
|
||||
},
|
||||
masterPasswordAuthenticationHash: newMasterPasswordHash,
|
||||
salt: args.email.trim().toLowerCase(),
|
||||
},
|
||||
unlockData: {
|
||||
kdf: {
|
||||
kdfType: 0,
|
||||
iterations: current.kdfIterations,
|
||||
memory: null,
|
||||
parallelism: null,
|
||||
},
|
||||
masterKeyWrappedUserKey: newKey,
|
||||
salt: args.email.trim().toLowerCase(),
|
||||
},
|
||||
kdf: 0,
|
||||
kdfIterations: current.kdfIterations,
|
||||
}),
|
||||
|
||||
@@ -20,6 +20,7 @@ import { readResponseBytesWithProgress } from '../download';
|
||||
import { loadVaultCoreSyncSnapshot } from './vault-sync';
|
||||
|
||||
type CipherLoginData = NonNullable<Cipher['login']>;
|
||||
const NODEWARDEN_WEB_REPAIR_HEADER = 'X-NodeWarden-Web';
|
||||
|
||||
export async function getFolders(authedFetch: AuthedFetch, cacheKey: string): Promise<Folder[]> {
|
||||
const body = await loadVaultCoreSyncSnapshot(authedFetch, cacheKey);
|
||||
@@ -933,7 +934,7 @@ export async function repairCipherUriChecksums(
|
||||
|
||||
const resp = await authedFetch(`/api/ciphers/${encodeURIComponent(cipher.id)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: { 'Content-Type': 'application/json', [NODEWARDEN_WEB_REPAIR_HEADER]: '1' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!resp.ok) throw new Error(await parseErrorMessage(resp, 'Repair URI checksum failed'));
|
||||
@@ -1092,9 +1093,14 @@ export async function repairCipherKeyMismatches(
|
||||
if (!cipher?.id || !looksLikeCipherString(cipher.key)) continue;
|
||||
if (!(await hasItemKeyFieldMismatch(cipher, userEnc, userMac))) continue;
|
||||
if (hasUnresolvedEncryptedFields(cipher)) continue;
|
||||
await updateCipher(authedFetch, session, cipher, draftFromDecryptedCipher(cipher), {
|
||||
preserveRevisionDate: true,
|
||||
});
|
||||
await updateCipher(
|
||||
authedFetch,
|
||||
session,
|
||||
cipher,
|
||||
draftFromDecryptedCipher(cipher),
|
||||
{ preserveRevisionDate: true },
|
||||
{ webRepair: true }
|
||||
);
|
||||
repaired += 1;
|
||||
}
|
||||
|
||||
@@ -1229,7 +1235,8 @@ export async function updateCipher(
|
||||
session: SessionState,
|
||||
cipher: Cipher,
|
||||
draft: VaultDraft,
|
||||
extraPayload?: Record<string, unknown>
|
||||
extraPayload?: Record<string, unknown>,
|
||||
options?: { webRepair?: boolean }
|
||||
): Promise<Cipher> {
|
||||
const payload = await buildCipherPayload(session, draft, cipher);
|
||||
if (extraPayload) {
|
||||
@@ -1238,7 +1245,10 @@ export async function updateCipher(
|
||||
|
||||
const resp = await authedFetch(`/api/ciphers/${encodeURIComponent(cipher.id)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(options?.webRepair ? { [NODEWARDEN_WEB_REPAIR_HEADER]: '1' } : {}),
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!resp.ok) throw new Error('Update item failed');
|
||||
|
||||
Reference in New Issue
Block a user