* Merge a partial state write with the latest on-disk state. * * Callers pass the keys they intentionally changed. Secret-bearing keys are * only written when they are in `updatedKeys`, so an old long-running * MailboxStore cannot overwrite a fresher Hub-rotated or divergence-cleared * secret t
(stateFile, nextState, updatedKeys)
| 155 | * @returns {Record<string, unknown>} |
| 156 | */ |
| 157 | function writeMergedMailboxStateFile(stateFile, nextState, updatedKeys) { |
| 158 | const releaseLock = acquireStateFileLock(stateFile); |
| 159 | try { |
| 160 | const next = isPlainState(nextState) ? nextState : {}; |
| 161 | const disk = readMailboxStateFile(stateFile); |
| 162 | const hasDiskState = isPlainState(disk); |
| 163 | const merged = hasDiskState ? { ...disk } : {}; |
| 164 | const updatedSet = updatedKeys ? new Set(Array.from(updatedKeys)) : null; |
| 165 | const keys = updatedSet ? Array.from(updatedSet) : Object.keys(next); |
| 166 | const touchesNodeSecretTuple = keys.some((key) => MAILBOX_NODE_SECRET_TUPLE_KEY_SET.has(key)); |
| 167 | const preserveDiskNodeSecretTuple = touchesNodeSecretTuple |
| 168 | && hasDiskState |
| 169 | && isHubRotatedNodeSecretState(disk) |
| 170 | && !isFullNodeSecretTupleUpdate(updatedSet); |
| 171 | |
| 172 | for (const key of keys) { |
| 173 | if (MAILBOX_NODE_SECRET_STATE_KEY_SET.has(key) && hasDiskState && (!updatedSet || !updatedSet.has(key))) { |
| 174 | continue; |
| 175 | } |
| 176 | if ( |
| 177 | MAILBOX_NODE_SECRET_TUPLE_KEY_SET.has(key) && |
| 178 | preserveDiskNodeSecretTuple && |
| 179 | !canApplyPartialNodeSecretTupleWrite(key, disk, next) |
| 180 | ) { |
| 181 | continue; |
| 182 | } |
| 183 | if (!Object.prototype.hasOwnProperty.call(next, key)) { |
| 184 | delete merged[key]; |
| 185 | continue; |
| 186 | } |
| 187 | merged[key] = next[key]; |
| 188 | } |
| 189 | |
| 190 | replaceStateFile(stateFile, merged); |
| 191 | return merged; |
| 192 | } finally { |
| 193 | releaseLock(); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | module.exports = { |
| 198 | PRIVATE_DIR_MODE, |
no test coverage detected