Skip to content

Commit 877831e

Browse files
author
Zhen
committed
Merge branch '1.0' into 1.1
2 parents c09ab5b + 20c702a commit 877831e

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

src/v1/internal/ch-node.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,27 @@ function loadFingerprint( serverId, knownHostsPath, cb ) {
7676
});
7777
}
7878

79-
function storeFingerprint(serverId, knownHostsPath, fingerprint) {
79+
const _lockFingerprintFromAppending = {};
80+
function storeFingerprint( serverId, knownHostsPath, fingerprint, cb ) {
81+
// we check if the serverId has been appended
82+
if(!!_lockFingerprintFromAppending[serverId]){
83+
// if it has, we ignore it
84+
return cb(null);
85+
}
86+
8087
// If file doesn't exist, create full path to it
8188
try {
8289
fs.accessSync(knownHostsPath);
8390
} catch (_) {
8491
mkFullPath(path.dirname(knownHostsPath));
8592
}
93+
8694
fs.appendFile(knownHostsPath, serverId + " " + fingerprint + EOL, "utf8", (err) => {
95+
delete _lockFingerprintFromAppending[serverId];
8796
if (err) {
8897
console.log(err);
8998
}
99+
return cb(err);
90100
});
91101
}
92102

@@ -154,8 +164,12 @@ const TrustStrategy = {
154164
if( knownFingerprint === serverFingerprint ) {
155165
onSuccess();
156166
} else if( knownFingerprint == null ) {
157-
storeFingerprint( serverId, knownHostsPath, serverFingerprint );
158-
onSuccess();
167+
storeFingerprint( serverId, knownHostsPath, serverFingerprint, (err) => {
168+
if (err) {
169+
return onFailure(err);
170+
}
171+
return onSuccess();
172+
});
159173
} else {
160174
onFailure(newError("Database encryption certificate has changed, and no longer " +
161175
"matches the certificate stored for " + serverId + " in `" + knownHostsPath +

test/internal/tls.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,60 @@ describe('trust-on-first-use', function() {
181181
done();
182182
});
183183
});
184+
185+
it('should not duplicate fingerprint entries', function(done) {
186+
// Assuming we only run this test on NodeJS with TOFU support
187+
if( !hasFeature("trust_on_first_use") ) {
188+
done();
189+
return;
190+
}
191+
192+
// Given
193+
var knownHostsPath = "build/known_hosts";
194+
if( fs.existsSync(knownHostsPath) ) {
195+
fs.unlinkSync(knownHostsPath);
196+
}
197+
fs.writeFileSync(knownHostsPath, '');
198+
199+
driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
200+
encrypted: true,
201+
trust: "TRUST_ON_FIRST_USE",
202+
knownHosts: knownHostsPath
203+
});
204+
205+
// When
206+
driver.session();
207+
driver.session();
208+
209+
// Then
210+
setTimeout(function() {
211+
var lines = {};
212+
fs.readFileSync(knownHostsPath, 'utf8')
213+
.split('\n')
214+
.filter(function(line) {
215+
return !! (line.trim());
216+
})
217+
.forEach(function(line) {
218+
if (!lines[line]) {
219+
lines[line] = 0;
220+
}
221+
lines[line]++;
222+
});
223+
224+
var duplicatedLines = Object
225+
.keys(lines)
226+
.map(function(line) {
227+
return lines[line];
228+
})
229+
.filter(function(count) {
230+
return count > 1;
231+
})
232+
.length;
233+
234+
expect( duplicatedLines ).toBe( 0 );
235+
done();
236+
}, 1000);
237+
});
184238

185239
it('should should give helpful error if database cert does not match stored certificate', function(done) {
186240
// Assuming we only run this test on NodeJS with TOFU support

0 commit comments

Comments
 (0)