Skip to content
This repository was archived by the owner on Dec 11, 2019. It is now read-only.

Commit b590743

Browse files
committed
Make writing state files "atomic"...
…to avoid possible file corruption if the browser is terminated between the open/write/close at the OS level… Auditor: @bsclifton Possibly addresses https://community.brave.com/t/payments-going-wrong-as-in-not-going-to-th e-visited-sites/175
1 parent f04777e commit b590743

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

app/ledger.js

+27-15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
addChangeListener - called when tabs render or gain focus
2020
*/
2121

22+
const crypto = require('crypto')
2223
const fs = require('fs')
2324
const os = require('os')
2425
const path = require('path')
@@ -577,7 +578,7 @@ var initialize = (paymentsEnabled) => {
577578
}
578579
getStateInfo(stateResult)
579580

580-
syncWriter(pathName(statePath), stateResult, { flushP: true }, () => {})
581+
atomicWriter(pathName(statePath), stateResult, { flushP: true }, () => {})
581582
})
582583
}
583584
} catch (ex) {
@@ -720,10 +721,10 @@ var updatePublisherInfo = () => {
720721

721722
if (entries.length > 0) data[publisher] = entries
722723
})
723-
syncWriter(pathName(publisherPath), data, () => {})
724-
syncWriter(pathName(scoresPath), synopsis.allN(), () => {})
724+
atomicWriter(pathName(publisherPath), data, () => {})
725+
atomicWriter(pathName(scoresPath), synopsis.allN(), () => {})
725726

726-
syncWriter(pathName(synopsisPath), synopsis, () => {})
727+
atomicWriter(pathName(synopsisPath), synopsis, () => {})
727728
if (!publisherInfo._internal.enabled) return
728729

729730
publisherInfo.synopsis = synopsisNormalizer()
@@ -1097,7 +1098,7 @@ var callback = (err, result, delayTime) => {
10971098
if ((i !== 0) && (i !== logs.length)) logs = logs.slice(i)
10981099
if (result) entries.push({ who: 'callback', what: result, when: underscore.now() })
10991100

1100-
syncWriter(pathName(logPath), entries, { flag: 'a' }, () => {})
1101+
atomicWriter(pathName(logPath), entries, { flag: 'a' }, () => {})
11011102
}
11021103

11031104
if (err) {
@@ -1117,7 +1118,7 @@ var callback = (err, result, delayTime) => {
11171118
}
11181119
cacheRuleSet(result.ruleset)
11191120

1120-
syncWriter(pathName(statePath), result, { flushP: true }, () => {})
1121+
atomicWriter(pathName(statePath), result, { flushP: true }, () => {})
11211122
run(delayTime)
11221123
}
11231124

@@ -1214,7 +1215,7 @@ var run = (delayTime) => {
12141215
result = client.vote(winner)
12151216
if (result) state = result
12161217
})
1217-
if (state) syncWriter(pathName(statePath), state, { flushP: true }, () => {})
1218+
if (state) atomicWriter(pathName(statePath), state, { flushP: true }, () => {})
12181219
} catch (ex) {
12191220
console.log('ledger client error(2): ' + ex.toString() + (ex.stack ? ('\n' + ex.stack) : ''))
12201221
}
@@ -1423,7 +1424,7 @@ var setPaymentInfo = (amount) => {
14231424
client.setBraveryProperties(bravery, (err, result) => {
14241425
if (err) return console.log('ledger setBraveryProperties: ' + err.toString())
14251426

1426-
if (result) syncWriter(pathName(statePath), result, { flushP: true }, () => {})
1427+
if (result) atomicWriter(pathName(statePath), result, { flushP: true }, () => {})
14271428
})
14281429
if (ledgerInfo.created) getPaymentInfo()
14291430
}
@@ -1473,7 +1474,9 @@ var networkConnected = underscore.debounce(() => {
14731474

14741475
var syncingP = {}
14751476

1476-
var syncWriter = (path, obj, options, cb) => {
1477+
var atomicWriter = (path, obj, options, cb) => {
1478+
var data, suffix
1479+
14771480
if (typeof options === 'function') {
14781481
cb = options
14791482
options = null
@@ -1488,19 +1491,28 @@ var syncWriter = (path, obj, options, cb) => {
14881491
}
14891492
syncingP[path] = true
14901493

1491-
if (ledgerInfo._internal.debugP) console.log('\nwriting ' + path)
1492-
fs.writeFile(path, JSON.stringify(obj, null, 2), options, (err) => {
1494+
data = JSON.stringify(obj, null, 2)
1495+
suffix = '-' + crypto.createHash('md5').update(data).digest('hex')
1496+
if (ledgerInfo._internal.debugP) console.log('\nwriting ' + path + suffix)
1497+
fs.writeFile(path + suffix, data, options, (err) => {
14931498
var deferred = syncingP[path]
14941499

14951500
delete syncingP[path]
14961501
if (typeof deferred === 'object') {
14971502
if (ledgerInfo._internal.debugP) console.log('\nrestarting ' + path)
1498-
syncWriter(path, deferred.obj, deferred.options, deferred.cb)
1503+
atomicWriter(path, deferred.obj, deferred.options, deferred.cb)
14991504
}
15001505

1501-
if (err) console.log('write error: ' + err.toString())
1506+
if (err) {
1507+
console.log('write error: ' + err.toString())
1508+
return cb(err)
1509+
}
15021510

1503-
cb(err)
1511+
if (ledgerInfo._internal.debugP) console.log('\nrenaming ' + path + suffix)
1512+
fs.rename(path + suffix, path, (err) => {
1513+
if (err) console.log('rename error: ' + err.toString())
1514+
cb(err)
1515+
})
15041516
})
15051517
}
15061518

@@ -1513,7 +1525,7 @@ var doneWriter = () => {
15131525
delete syncingP[path]
15141526
if (ledgerInfo._internal.debugP) console.log('\nflushing ' + path)
15151527
deferred.options.flushP = true
1516-
syncWriter(path, deferred.obj, deferred.options, deferred.cb)
1528+
atomicWriter(path, deferred.obj, deferred.options, deferred.cb)
15171529
})
15181530
}
15191531

0 commit comments

Comments
 (0)