From 553aa40fb3c702a414fbd3785cb7b9c03e6ae095 Mon Sep 17 00:00:00 2001 From: Klemek Date: Thu, 20 Jun 2019 19:15:49 +0200 Subject: [PATCH] generating git_secret at start --- .gitignore | 3 +- src/app.js | 56 +++++++++++++++++++--- src/config.default.json | 2 +- test/app.test.js | 101 +++++++++++++++++++++++++++------------- 4 files changed, 120 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index aba5ca9..606eb9f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ /config.json /config.example.json /data -/test_data \ No newline at end of file +/test_data +/git_secret \ No newline at end of file diff --git a/src/app.js b/src/app.js index 4319149..05d62e1 100644 --- a/src/app.js +++ b/src/app.js @@ -14,6 +14,16 @@ const cons = { error: '\x1b[31m✘\x1b[0m %s', }; +const randStr = (length) => { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +}; + module.exports = (config) => { const fw = require('./file_walker')(config); const renderer = require('./renderer')(config); @@ -25,16 +35,18 @@ module.exports = (config) => { const articles = {}; let lastRSS = ''; + let webhookSecret; /** * Fetch articles from the data folder and send success as a response - * @param callback + * @param success + * @param error */ - const reload = (callback) => { + const reload = (success, error) => { fw.fetchArticles((err, dict) => { if (err) { - callback(false); - return console.error(cons.error, 'loading articles : ' + err); + console.error(cons.error, 'error loading articles : ' + err); + return error ? error() : null; } Object.keys(articles).forEach((key) => delete articles[key]); Object.keys(dict).forEach((key) => articles[key] = dict[key]); @@ -46,12 +58,41 @@ module.exports = (config) => { lastRSS = ''; - callback(true); + success(); }); }; if (config['test']) app.reload = reload; + /** + * Fetch or create secret token for git webhook + * @param success + * @param error + */ + const checkSecret = (success, error) => { + if (!config['modules']['webhook']) + success(); + fs.readFile(config['webhook']['secret_file'], {encoding: 'UTF-8'}, (err, data) => { + if (err) { + webhookSecret = randStr(32); + fs.writeFile(config['webhook']['secret_file'], webhookSecret, {encoding: 'UTF-8'}, (err) => { + if (err) { + console.error(cons.error, 'error creating secret : ' + err); + return error ? error() : null; + } + console.log(cons.ok,'created git secret at '+config['webhook']['secret_file']); + success(); + }); + } else { + webhookSecret = data; + console.log(cons.ok,'loaded git secret from '+config['webhook']['secret_file']); + success(); + } + }); + }; + if (config['test']) + app.checkSecret = checkSecret; + /** * Render the page with the view engine and catch errors * @param res @@ -180,11 +221,12 @@ module.exports = (config) => { // must be use in a server.js to start the server app.start = () => { - reload((res) => { - if (res) + reload(() => { + checkSecret(() => { app.listen(config['node_port'], () => { console.log(cons.ok, `gitblog.md server listening on port ${config['node_port']}`); }); + }); }); }; diff --git a/src/config.default.json b/src/config.default.json index d5ac59a..027b7d2 100644 --- a/src/config.default.json +++ b/src/config.default.json @@ -30,7 +30,7 @@ }, "webhook": { "endpoint": "/webhook", - "secretFile": "git_secret" + "secret_file": "git_secret" }, "showdown": { "parseImgDimensions": true, diff --git a/test/app.test.js b/test/app.test.js index 2342920..900da2a 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -22,13 +22,10 @@ config['rss']['length'] = 2; const app = require('../src/app')(config); -beforeEach((done) => { +beforeEach((done, fail) => { utils.deleteFolderSync(dataDir); fs.mkdirSync(dataDir); - app.reload((res) => { - expect(res).toBe(true); - done(); - }); + app.reload(done, fail); }); afterAll(() => { @@ -60,7 +57,7 @@ describe('Test root path', () => { done(); }); }); - test('200 2 articles', (done) => { + test('200 2 articles', (done, fail) => { utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05'), path.join(dataDir, '2018', '05', '05') @@ -70,18 +67,62 @@ describe('Test root path', () => { path.join(dataDir, '2018', '05', '05', 'index.md') ]); fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= articles.length %>'); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/').then((response) => { expect(response.statusCode).toBe(200); expect(response.text).toBe('articles 2'); done(); }); - }); + }, fail); }); }); +describe('Test check secret', () => { + const secretFile = 'git_secret'; + const tmpSecretFile = 'tmp_git_secret'; + beforeEach(() => { + if (fs.existsSync(secretFile)) + fs.renameSync(secretFile, tmpSecretFile); + }); + + afterEach(() => { + if (fs.existsSync(tmpSecretFile)) { + fs.renameSync(tmpSecretFile, secretFile); + } else if (fs.existsSync(secretFile)) { + fs.unlinkSync(secretFile); //remove secret file if remaining + } + }); + + test('no check if not activated', (done, fail) => { + config['modules']['webhook'] = false; + app.checkSecret(() => { + config['modules']['webhook'] = true; + done(); + }, () => { + config['modules']['webhook'] = true; + fail(); + }); + }); + test('create if not exists', (done, fail) => { + if (fs.existsSync(secretFile)) + fs.unlinkSync(secretFile); + app.checkSecret(() => { + expect(fs.existsSync(secretFile)).toBe(true); + expect(fs.readFileSync(secretFile).length).toBeGreaterThan(0); + done(); + }, fail); + }); + test('read if exists', (done, fail) => { + fs.writeFileSync(secretFile,'secret value'); + app.checkSecret(() => { + expect(fs.existsSync(secretFile)).toBe(true); + expect(fs.readFileSync(secretFile, {encoding:'UTF-8'})).toBe('secret value'); + done(); + }, fail); + }); +}); + describe('Test RSS feed', () => { test('404 rss deactivated', (done) => { config['modules']['rss'] = false; @@ -99,7 +140,7 @@ describe('Test RSS feed', () => { done(); }); }); - test('200 2 rss items', (done) => { + test('200 2 rss items', (done, fail) => { utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05'), path.join(dataDir, '2018', '05', '05') @@ -108,17 +149,16 @@ describe('Test RSS feed', () => { path.join(dataDir, '2019', '05', '05', 'index.md'), path.join(dataDir, '2018', '05', '05', 'index.md') ]); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/rsstest').then((response) => { expect(response.statusCode).toBe(200); expect(response.text.length).toBeGreaterThan(0); expect(response.text.split('').length).toBe(3); done(); - }); + }, fail); }); }); - test('200 max rss items', (done) => { + test('200 max rss items', (done, fail) => { utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05'), path.join(dataDir, '2018', '05', '05'), @@ -129,14 +169,13 @@ describe('Test RSS feed', () => { path.join(dataDir, '2018', '05', '05', 'index.md'), path.join(dataDir, '2017', '05', '05', 'index.md') ]); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/rsstest').then((response) => { expect(response.statusCode).toBe(200); expect(response.text.length).toBeGreaterThan(0); expect(response.text.split('').length).toBe(3); done(); - }); + }, fail); }); }); }); @@ -149,59 +188,55 @@ describe('Test articles rendering', () => { }); }); - test('500 no template', (done) => { + test('500 no template', (done, fail) => { utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello'); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/2019/05/05/hello/').then((response) => { expect(response.statusCode).toBe(500); done(); - }); + }, fail); }); }); - test('200 rendered article', (done) => { + test('200 rendered article', (done, fail) => { utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello'); fs.writeFileSync(path.join(dataDir, testTemplate), '<%- article.content %><%- `reload` %>'); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/2019/05/05/hello/').then((response) => { expect(response.statusCode).toBe(200); expect(response.text).toBe('

Hello

reload'); done(); - }); + }, fail); }); }); - test('200 other url', (done) => { + test('200 other url', (done, fail) => { utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); utils.createEmptyFiles([ path.join(dataDir, '2019', '05', '05', 'index.md'), path.join(dataDir, testTemplate) ]); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/2019/05/05/anything/').then((response) => { expect(response.statusCode).toBe(200); done(); - }); + }, fail); }); }); - test('200 other url 2', (done) => { + test('200 other url 2', (done, fail) => { utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); utils.createEmptyFiles([ path.join(dataDir, '2019', '05', '05', 'index.md'), path.join(dataDir, testTemplate) ]); - app.reload((res) => { - expect(res).toBe(true); + app.reload(() => { request(app).get('/2019/05/05/').then((response) => { expect(response.statusCode).toBe(200); done(); - }); + }, fail); }); }); });