Compare commits

...

17 Commits

Author SHA1 Message Date
snyk-bot aaf0d71992 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-EJS-6689533
2024-04-30 00:16:19 +00:00
Klemek ab23e4aa3c Create docker.yml 2021-06-09 15:34:57 +02:00
Klemek ab573f91ee Merge pull request #58 from Klemek/f-stats-all
/stats?all=true
2021-04-06 10:10:00 +02:00
Klemek 8a9b9cdcfe /stats?all=true 2021-04-06 09:58:51 +02:00
Klemek e56867a269 Update bot_detector.js 2021-04-04 23:33:59 +02:00
Klemek 8e795c6371 Merge pull request #57 from Klemek/f-ignore-bots
ignore bots in hit counter
2021-04-04 23:31:38 +02:00
Klemek c3e53c7df8 more unit tests 2021-04-04 23:24:33 +02:00
Klemek 404b02830d unit testing 2021-04-04 22:48:21 +02:00
Klemek 2fe9a8fecd updated package.json 2021-04-04 21:57:54 +02:00
Klemek 078f3d7416 updated readme 2021-04-04 21:57:16 +02:00
Klemek d69e10202c bot detector handling requests and disabling hit counter 2021-04-04 21:57:09 +02:00
Klemek 140e472e29 bot detector base code 2021-04-04 21:56:39 +02:00
Klemek 823d97f4bb parseInt redis values 2021-03-30 20:19:37 +02:00
Klemek f7167a85a8 1.3.1: current visitors 2021-03-30 20:16:15 +02:00
Klemek 4a3b8267ec update Dockerfile 2021-03-30 19:56:08 +02:00
Klemek d0bebcba87 fix Dockerfile 2021-03-30 19:53:26 +02:00
Klemek 56d7993116 bump to node 15 2021-03-30 19:47:18 +02:00
13 changed files with 681 additions and 138 deletions
+34
View File
@@ -0,0 +1,34 @@
name: Docker
on: ["push", "pull_request"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build
uses: docker/build-push-action@v2
with:
context: ./
file: ./Dockerfile
builder: ${{ steps.buildx.outputs.name }}
push: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
+1
View File
@@ -2,6 +2,7 @@
/node_modules /node_modules
/config.json /config.json
/config.example.json /config.example.json
/robots_list.json
/data /data
/data/* /data/*
/test_data /test_data
+5 -1
View File
@@ -1,12 +1,16 @@
FROM node:14 FROM node:15
# Create app directory # Create app directory
WORKDIR /usr/src/app WORKDIR /usr/src/app
VOLUME [ "/usr/src/app/data" ]
# Install app dependencies # Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied # A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+) # where available (npm@5+)
COPY package*.json ./ COPY package*.json ./
COPY src/postinstall.js ./src/postinstall.js
COPY src/config.default.json ./src/config.default.json
RUN npm install RUN npm install
# If you are building your code for production # If you are building your code for production
+5
View File
@@ -336,6 +336,11 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link
* `hit_counter` * `hit_counter`
* `unique_visitor_timeout`: (default: 7200000 / 2h) * `unique_visitor_timeout`: (default: 7200000 / 2h)
specify the time (in ms) before a visitor can be accounted again specify the time (in ms) before a visitor can be accounted again
* `robots`
* `list_url`: (default: https://raw.githubusercontent.com/atmire/COUNTER-Robots/master/COUNTER_Robots_list.json)
url to fetch for web crawlers patterns
* `list_file`: (default: robots_list.json)
file to store web crawlers patterns
* `redis` * `redis`
Options to connect to redis (see [redis options](https://github.com/NodeRedis/node-redis#options-object-properties) for more info) Options to connect to redis (see [redis options](https://github.com/NodeRedis/node-redis#options-object-properties) for more info)
* `host`: (default: localhost) * `host`: (default: localhost)
+217 -41
View File
@@ -1,17 +1,18 @@
{ {
"name": "gitblog.md", "name": "gitblog.md",
"version": "1.2.8", "version": "1.3.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "1.2.8", "name": "gitblog.md",
"version": "1.3.3",
"hasInstallScript": true, "hasInstallScript": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@iarna/toml": "^2.2.3", "@iarna/toml": "^2.2.3",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"ejs": "^3.1.6", "ejs": "^3.1.10",
"express": "^4.17.1", "express": "^4.17.1",
"express-rate-limit": "^5.0.0", "express-rate-limit": "^5.0.0",
"fa-diagrams": "^1.0.3", "fa-diagrams": "^1.0.3",
@@ -1048,9 +1049,9 @@
} }
}, },
"node_modules/async": { "node_modules/async": {
"version": "0.9.2", "version": "3.2.5",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
}, },
"node_modules/async-limiter": { "node_modules/async-limiter": {
"version": "1.0.1", "version": "1.0.1",
@@ -1460,6 +1461,7 @@
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": { "dependencies": {
"ansi-styles": "^3.2.1", "ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
@@ -1993,11 +1995,11 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
}, },
"node_modules/ejs": { "node_modules/ejs": {
"version": "3.1.6", "version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"dependencies": { "dependencies": {
"jake": "^10.6.1" "jake": "^10.8.5"
}, },
"bin": { "bin": {
"ejs": "bin/cli.js" "ejs": "bin/cli.js"
@@ -2093,6 +2095,7 @@
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
} }
@@ -2939,11 +2942,30 @@
} }
}, },
"node_modules/filelist": { "node_modules/filelist": {
"version": "1.0.2", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"dependencies": { "dependencies": {
"minimatch": "^3.0.4" "minimatch": "^5.0.1"
}
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
@@ -4084,6 +4106,7 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true,
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@@ -4707,22 +4730,97 @@
} }
}, },
"node_modules/jake": { "node_modules/jake": {
"version": "10.8.2", "version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
"dependencies": { "dependencies": {
"async": "0.9.x", "async": "^3.2.3",
"chalk": "^2.4.2", "chalk": "^4.0.2",
"filelist": "^1.0.1", "filelist": "^1.0.4",
"minimatch": "^3.0.4" "minimatch": "^3.1.2"
}, },
"bin": { "bin": {
"jake": "bin/cli.js" "jake": "bin/cli.js"
}, },
"engines": {
"node": ">=10"
}
},
"node_modules/jake/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/jake/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/jake/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/jake/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/jake/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/jake/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": { "engines": {
"node": "*" "node": "*"
} }
}, },
"node_modules/jake/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/jest": { "node_modules/jest": {
"version": "24.9.0", "version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz",
@@ -6079,6 +6177,7 @@
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
}, },
@@ -8172,6 +8271,7 @@
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": { "dependencies": {
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
}, },
@@ -9714,9 +9814,9 @@
"dev": true "dev": true
}, },
"async": { "async": {
"version": "0.9.2", "version": "3.2.5",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
}, },
"async-limiter": { "async-limiter": {
"version": "1.0.1", "version": "1.0.1",
@@ -10056,6 +10156,7 @@
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": { "requires": {
"ansi-styles": "^3.2.1", "ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
@@ -10492,11 +10593,11 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
}, },
"ejs": { "ejs": {
"version": "3.1.6", "version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"requires": { "requires": {
"jake": "^10.6.1" "jake": "^10.8.5"
} }
}, },
"emoji-regex": { "emoji-regex": {
@@ -10573,7 +10674,8 @@
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
}, },
"escodegen": { "escodegen": {
"version": "1.12.0", "version": "1.12.0",
@@ -11219,11 +11321,29 @@
} }
}, },
"filelist": { "filelist": {
"version": "1.0.2", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"requires": { "requires": {
"minimatch": "^3.0.4" "minimatch": "^5.0.1"
},
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
}
},
"minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"requires": {
"brace-expansion": "^2.0.1"
}
}
} }
}, },
"fill-range": { "fill-range": {
@@ -12063,7 +12183,8 @@
"has-flag": { "has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
}, },
"has-symbols": { "has-symbols": {
"version": "1.0.2", "version": "1.0.2",
@@ -12545,14 +12666,67 @@
} }
}, },
"jake": { "jake": {
"version": "10.8.2", "version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
"requires": { "requires": {
"async": "0.9.x", "async": "^3.2.3",
"chalk": "^2.4.2", "chalk": "^4.0.2",
"filelist": "^1.0.1", "filelist": "^1.0.4",
"minimatch": "^3.0.4" "minimatch": "^3.1.2"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
}
} }
}, },
"jest": { "jest": {
@@ -13657,6 +13831,7 @@
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@@ -15322,6 +15497,7 @@
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": { "requires": {
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
} }
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "gitblog.md", "name": "gitblog.md",
"version": "1.3.0", "version": "1.3.3",
"description": "A static blog using Markdown pulled from your git repository.", "description": "A static blog using Markdown pulled from your git repository.",
"main": "src/server.js", "main": "src/server.js",
"dependencies": { "dependencies": {
"@iarna/toml": "^2.2.3", "@iarna/toml": "^2.2.3",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"ejs": "^3.1.6", "ejs": "^3.1.10",
"express": "^4.17.1", "express": "^4.17.1",
"express-rate-limit": "^5.0.0", "express-rate-limit": "^5.0.0",
"fa-diagrams": "^1.0.3", "fa-diagrams": "^1.0.3",
+40 -10
View File
@@ -61,6 +61,23 @@ module.exports = (config) => {
} }
}, },
); );
const botDetector = require('./bot_detector')(config);
botDetector.load((status, err) => {
switch (status) {
case botDetector.status.FETCH_OK:
console.log(cons.ok, 'fetched robots list');
break;
case botDetector.status.FETCH_ERROR:
console.error(cons.error, 'error fetching robots list : ' + err);
break;
case botDetector.status.READ_OK:
console.log(cons.ok, `read robots list: ${botDetector.count}`);
break;
case botDetector.status.READ_ERROR:
console.error(cons.error, 'error reading robots list : ' + err);
break;
}
});
// set view engine from configuration // set view engine from configuration
app.set('view engine', config['view_engine']); app.set('view engine', config['view_engine']);
@@ -145,6 +162,9 @@ module.exports = (config) => {
}); });
app.use(limiter); app.use(limiter);
//detect robots
app.use(botDetector.handle);
//log request at result end //log request at result end
app.use((req, res, next) => { app.use((req, res, next) => {
if (config['access_log']) { if (config['access_log']) {
@@ -168,7 +188,7 @@ module.exports = (config) => {
if (err) { if (err) {
showError(req, res, 404); showError(req, res, 404);
} else { } else {
hc.count(req, '/', () => { hc.count(req, '/', req.isRobot, () => {
render(req, res, homePath, render(req, res, homePath,
{ {
articles: Object.values(articles) articles: Object.values(articles)
@@ -181,12 +201,25 @@ module.exports = (config) => {
}); });
app.get('/stats', (req, res) => { app.get('/stats', (req, res) => {
if (config['modules']['hit_counter']) { if (config['modules']['hit_counter']) {
if (req.query['all']) {
const keys = Object.keys(articles).filter(key => !articles[key].draft);
keys.unshift('/');
const read = (i, outputData) => {
if (i >= keys.length) {
res.json(outputData);
} else {
hc.read(keys[i], (data) => {
outputData.push(data);
read(i + 1, outputData);
});
}
};
read(0, []);
} else {
hc.read('/', (data) => { hc.read('/', (data) => {
res.json({ res.json(data);
hits: data.hits,
visitors: data.visitors,
});
}); });
}
} else { } else {
showError(req, res, 404); showError(req, res, 404);
} }
@@ -268,16 +301,13 @@ module.exports = (config) => {
} else if (req.path.endsWith('stats')) { } else if (req.path.endsWith('stats')) {
if (config['modules']['hit_counter']) { if (config['modules']['hit_counter']) {
hc.read(articlePath, (data) => { hc.read(articlePath, (data) => {
res.json({ res.json(data);
hits: data.hits,
visitors: data.visitors,
});
}); });
} else { } else {
showError(req, res, 404); showError(req, res, 404);
} }
} else { } else {
hc.count(req, articlePath, () => { hc.count(req, articlePath, req.isRobot, () => {
renderer.render(article.realPath, (err, html) => { renderer.render(article.realPath, (err, html) => {
if (err) { if (err) {
console.log(cons.error, `failed to render article ${req.path} : ${err}`); console.log(cons.error, `failed to render article ${req.path} : ${err}`);
+66
View File
@@ -0,0 +1,66 @@
const https = require('https');
const fs = require('fs');
module.exports = (config) => {
const _this = {
status: {
FETCH_OK: 1,
FETCH_ERROR: 2,
READ_OK: 3,
READ_ERROR: 4,
},
count: [],
regex: null,
};
const fetchList = (cb) => {
https.get(config['robots']['list_url'], (res) => {
if (res.statusCode !== 200) {
cb(res.statusCode);
} else {
const file = fs.createWriteStream(config['robots']['list_file']);
res.pipe(file);
file.on('finish', () => {
file.close(cb);
});
}
}).on('error', (err) => {
cb(err.message);
});
};
const readFile = (cb) => {
fs.readFile(config['robots']['list_file'], { encoding: 'utf-8' }, (err, data) => {
if (err) {
cb(err, undefined);
} else {
try {
cb(undefined, JSON.parse(data));
} catch (err) {
cb(err, undefined);
}
}
});
};
_this.load = (cb) => {
fetchList((err) => {
cb(err ? _this.status.FETCH_ERROR : _this.status.FETCH_OK, err);
readFile((err, data) => {
if (!err) {
_this.count = data.length;
_this.regex = new RegExp('(' + data.filter(v => v['pattern']).map(v => v['pattern'])
.join('|') + ')');
}
cb(err ? _this.status.READ_ERROR : _this.status.READ_OK, err);
});
});
};
_this.handle = (req, res, next) => {
req.isRobot = !!((req.headers['user-agent'] || '').match(_this.regex));
next();
};
return _this;
};
+4
View File
@@ -63,6 +63,10 @@
"hit_counter": { "hit_counter": {
"unique_visitor_timeout": 7200000 "unique_visitor_timeout": 7200000
}, },
"robots": {
"list_url": "https://raw.githubusercontent.com/atmire/COUNTER-Robots/master/COUNTER_Robots_list.json",
"list_file": "robots_list.json"
},
"redis": { "redis": {
"host": "localhost", "host": "localhost",
"port": 6379 "port": 6379
+26 -8
View File
@@ -8,15 +8,15 @@ module.exports = (config, onConnect, onError) => {
const visitors = {}; const visitors = {};
const count = (req, path, cb) => { const count = (req, path, disable, cb) => {
if (!client.connected) { if (!client.connected || disable) {
cb(); cb();
} else { } else {
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const key = path + ':' + ip; visitors[path] = (visitors[path] || {});
const now = Date.now(); const now = Date.now();
const isNewVisitor = (now - (visitors[key] || 0)) > config['hit_counter']['unique_visitor_timeout']; const isNewVisitor = (now - (visitors[path][ip] || 0)) > config['hit_counter']['unique_visitor_timeout'];
visitors[key] = now; visitors[path][ip] = now;
client client
.multi() .multi()
.hincrby(path, 'h', 1) .hincrby(path, 'h', 1)
@@ -25,17 +25,35 @@ module.exports = (config, onConnect, onError) => {
} }
}; };
const cleanVisitors = (path) => {
visitors[path] = (visitors[path] || {});
const now = Date.now();
let count = 0;
for (let ip in visitors[path]) {
if ((now - visitors[path][ip]) > config['hit_counter']['unique_visitor_timeout']) {
delete visitors[path][ip];
} else {
count++;
}
}
return count;
};
const read = (path, cb) => { const read = (path, cb) => {
if (!client.connected) { if (!client.connected) {
cb({ cb({
path: path,
hits: 0, hits: 0,
visitors: 0, total_visitors: 0,
current_visitors: cleanVisitors(path),
}); });
} else { } else {
client.hgetall(path, (_, value) => { client.hgetall(path, (_, value) => {
cb({ cb({
hits: value ? value.h || 0 : 0, path: path,
visitors: value ? value.v || 0 : 0, hits: value ? parseInt(value.h) || 0 : 0,
total_visitors: value ? parseInt(value.v) || 0 : 0,
current_visitors: cleanVisitors(path),
}); });
}); });
} }
+110 -49
View File
@@ -197,22 +197,6 @@ describe('Test root path', () => {
}); });
}, fail); }, fail);
}); });
test('404 index no stats', (done) => {
request(app).get('/stats')
.then((response) => {
expect(response.statusCode).toBe(404);
done();
});
});
test('200 index stats', (done) => {
config['modules']['hit_counter'] = true;
request(app).get('/stats')
.then((response) => {
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({ hits: 0, visitors: 0 });
done();
});
});
}); });
describe('Test RSS feed', () => { describe('Test RSS feed', () => {
@@ -451,41 +435,8 @@ describe('Test articles rendering', () => {
}); });
}, fail); }, fail);
}); });
test('404 article no stats', (done) => {
utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05') ]);
utils.createEmptyFiles([
path.join(dataDir, '2019', '05', '05', 'index.md'),
path.join(dataDir, testTemplate),
]);
app.reload(() => {
request(app).get('/2019/05/05/hello/stats')
.then((response) => {
expect(response.statusCode).toBe(404);
done();
});
});
});
test('200 index stats', (done) => {
config['modules']['hit_counter'] = true;
utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05') ]);
utils.createEmptyFiles([
path.join(dataDir, '2019', '05', '05', 'index.md'),
path.join(dataDir, testTemplate),
]);
app.reload(() => {
request(app).get('/2019/05/05/anything/stats')
.then((response) => {
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({ hits: 0, visitors: 0 });
done();
});
});
});
}); });
describe('Test static files', () => { describe('Test static files', () => {
test('404 invalid file no error page', (done) => { test('404 invalid file no error page', (done) => {
request(app).get('/somefile.txt') request(app).get('/somefile.txt')
@@ -566,3 +517,113 @@ describe('Test other requests', () => {
}); });
}); });
}); });
describe('Test stats', () => {
test('404 index no stats', (done) => {
request(app).get('/stats')
.then((response) => {
expect(response.statusCode).toBe(404);
done();
});
});
test('200 index stats', (done) => {
config['modules']['hit_counter'] = true;
request(app).get('/stats')
.then((response) => {
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({
path: '/',
hits: 0,
total_visitors: 0,
current_visitors: 0,
});
done();
});
});
test('200 index stats all no article', (done) => {
config['modules']['hit_counter'] = true;
app.reload(() => {
request(app).get('/stats?all=true')
.then((response) => {
expect(response.statusCode).toBe(200);
expect(response.body).toEqual([
{
path: '/',
hits: 0,
total_visitors: 0,
current_visitors: 0,
},
]);
done();
});
});
});
test('200 index stats all 2 article 1 drafted', (done) => {
config['modules']['hit_counter'] = true;
utils.createEmptyDirs([
path.join(dataDir, '2019', '05', '05'),
path.join(dataDir, '2019', '04', '05'),
]);
utils.createEmptyFiles([
path.join(dataDir, '2019', '05', '05', 'index.md'),
path.join(dataDir, '2019', '04', '05', 'draft.md'),
]);
app.reload(() => {
request(app).get('/stats?all=true')
.then((response) => {
expect(response.statusCode).toBe(200);
expect(response.body).toEqual([
{
path: '/',
hits: 0,
total_visitors: 0,
current_visitors: 0,
},
{
path: '2019/05/05',
hits: 0,
total_visitors: 0,
current_visitors: 0,
},
]);
done();
});
});
});
test('404 article no stats', (done) => {
utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05') ]);
utils.createEmptyFiles([
path.join(dataDir, '2019', '05', '05', 'index.md'),
path.join(dataDir, testTemplate),
]);
app.reload(() => {
request(app).get('/2019/05/05/hello/stats')
.then((response) => {
expect(response.statusCode).toBe(404);
done();
});
});
});
test('200 article stats', (done) => {
config['modules']['hit_counter'] = true;
utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05') ]);
utils.createEmptyFiles([
path.join(dataDir, '2019', '05', '05', 'index.md'),
path.join(dataDir, testTemplate),
]);
app.reload(() => {
request(app).get('/2019/05/05/anything/stats')
.then((response) => {
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({
path: '2019/05/05',
hits: 0,
total_visitors: 0,
current_visitors: 0,
});
done();
});
});
});
});
+116
View File
@@ -0,0 +1,116 @@
const fs = require('fs');
const utils = require('./test_utils');
const dataDir = 'test_data';
const config = {
robots: {
list_url: '',
list_file: `${dataDir}/robots_list.json`,
},
};
beforeAll(() => {
utils.deleteFolderSync(dataDir);
fs.mkdirSync(dataDir);
});
afterAll(() => {
if (fs.existsSync(dataDir)) {
utils.deleteFolderSync(dataDir);
}
});
const botDetector = require('../src/bot_detector')(config);
describe('load()', () => {
test('success', (done) => {
config.robots = {
list_url: 'https://raw.githubusercontent.com/atmire/COUNTER-Robots/master/COUNTER_Robots_list.json',
list_file: `${dataDir}/robots_list_success.json`,
};
let count = 0;
botDetector.load((status, err) => {
expect(err).not.toBeDefined();
expect(status).toBe(count === 0 ? botDetector.status.FETCH_OK : botDetector.status.READ_OK);
if (count > 0) {
done();
}
count++;
});
});
test('fetch and file failure', (done) => {
let count = 0;
config.robots = {
list_url: 'https://blog.klemek.fr/invalid.json',
list_file: `${dataDir}/robots_list_fail_1.json`,
};
botDetector.load((status) => {
expect(status).toBe(count === 0 ? botDetector.status.FETCH_ERROR : botDetector.status.READ_ERROR);
if (count > 0) {
done();
}
count++;
});
});
test('fetch failure and file ok', (done) => {
let count = 0;
config.robots = {
list_url: 'https://blog.klemek.fr/invalid.json',
list_file: `${dataDir}/robots_list_fail_2.json`,
};
fs.writeFile(config.robots.list_file, '[]\n', { encoding: 'utf-8' }, () => {
botDetector.load((status) => {
expect(status).toBe(count === 0 ? botDetector.status.FETCH_ERROR : botDetector.status.READ_OK);
if (count > 0) {
done();
}
count++;
});
});
});
});
describe('handle()', () => {
beforeAll((done) => {
config.robots = {
list_url: 'https://blog.klemek.fr/invalid.json',
list_file: `${dataDir}/robots_list_fake.json`,
};
fs.writeFile(config.robots.list_file, '[{"pattern":"bot"}]\n', { encoding: 'utf-8' }, () => {
botDetector.load((status) => {
if (status !== botDetector.status.FETCH_ERROR) {
done();
}
});
});
});
test('not bot', (done) => {
const req = {
headers: {
'user-agent': 'my user agent',
},
};
botDetector.handle(req, null, () => {
expect(req.isRobot).toBeFalsy();
done();
});
});
test('bot', (done) => {
const req = {
headers: {
'user-agent': 'bot',
},
};
botDetector.handle(req, null, () => {
expect(req.isRobot).toBeTruthy();
done();
});
});
});
+51 -23
View File
@@ -37,14 +37,21 @@ test('options passed to redis', () => {
expect(mockClient.options).toEqual(config['redis']); expect(mockClient.options).toEqual(config['redis']);
}); });
describe('read()', () => {
beforeEach(() => { beforeEach(() => {
mockClient.hgetall = (_, cb) => { mockClient.hgetall = (_, cb) => {
cb(); cb();
}; };
}); mockClient.multi = () => mockClient;
mockClient.hincrby = () => mockClient;
mockClient.exec = (cb) => {
cb();
};
config['hit_counter']['unique_visitor_timeout'] = -1;
});
test('read path', (done) => { describe('read()', () => {
test('normal', (done) => {
mockClient.hgetall = (path, cb) => { mockClient.hgetall = (path, cb) => {
expect(path).toBe('/test/path/'); expect(path).toBe('/test/path/');
cb(undefined, { h: 12, v: 34 }); cb(undefined, { h: 12, v: 34 });
@@ -52,12 +59,13 @@ describe('read()', () => {
hc.read('/test/path/', (data) => { hc.read('/test/path/', (data) => {
expect(data).toBeDefined(); expect(data).toBeDefined();
expect(data.hits).toBe(12); expect(data.hits).toBe(12);
expect(data.visitors).toBe(34); expect(data.total_visitors).toBe(34);
expect(data.current_visitors).toBe(0);
done(); done();
}); });
}); });
test('read path with error', (done) => { test('with error', (done) => {
mockClient.hgetall = (path, cb) => { mockClient.hgetall = (path, cb) => {
expect(path).toBe('/test/path/'); expect(path).toBe('/test/path/');
cb('error', undefined); cb('error', undefined);
@@ -65,12 +73,13 @@ describe('read()', () => {
hc.read('/test/path/', (data) => { hc.read('/test/path/', (data) => {
expect(data).toBeDefined(); expect(data).toBeDefined();
expect(data.hits).toBe(0); expect(data.hits).toBe(0);
expect(data.visitors).toBe(0); expect(data.total_visitors).toBe(0);
expect(data.current_visitors).toBe(0);
done(); done();
}); });
}); });
test('read path with error 2', (done) => { test('with error 2', (done) => {
mockClient.hgetall = (path, cb) => { mockClient.hgetall = (path, cb) => {
expect(path).toBe('/test/path/'); expect(path).toBe('/test/path/');
cb(undefined, {}); cb(undefined, {});
@@ -78,22 +87,41 @@ describe('read()', () => {
hc.read('/test/path/', (data) => { hc.read('/test/path/', (data) => {
expect(data).toBeDefined(); expect(data).toBeDefined();
expect(data.hits).toBe(0); expect(data.hits).toBe(0);
expect(data.visitors).toBe(0); expect(data.total_visitors).toBe(0);
expect(data.current_visitors).toBe(0);
done(); done();
}); });
}); });
test('1 visitor', (done) => {
config['hit_counter']['unique_visitor_timeout'] = 1000;
hc.count({
headers: {},
connection: { remoteAddress: 'test1' },
}, '/test/path/5', false, () => {
hc.read('/test/path/5', (data) => {
expect(data).toBeDefined();
expect(data.current_visitors).toBe(1);
done();
});
});
});
test('cleaned old visitor', (done) => {
hc.count({
headers: {},
connection: { remoteAddress: 'test1' },
}, '/test/path/5', false, () => {
hc.read('/test/path/5', (data) => {
expect(data).toBeDefined();
expect(data.current_visitors).toBe(0);
done();
});
});
});
}); });
describe('count()', () => { describe('count()', () => {
beforeEach(() => {
mockClient.multi = () => mockClient;
mockClient.hincrby = () => mockClient;
mockClient.exec = (cb) => {
cb();
};
config['hit_counter']['unique_visitor_timeout'] = -1;
});
test('simple visit', (done) => { test('simple visit', (done) => {
let multiCalled = false; let multiCalled = false;
let execCalled = false; let execCalled = false;
@@ -117,7 +145,7 @@ describe('count()', () => {
hc.count({ hc.count({
headers: {}, headers: {},
connection: { remoteAddress: 'test1' }, connection: { remoteAddress: 'test1' },
}, '/test/path/1', () => { }, '/test/path/1', false, () => {
expect(multiCalled).toBeTruthy(); expect(multiCalled).toBeTruthy();
expect(hincrbyCalls).toEqual([ expect(hincrbyCalls).toEqual([
[ [
@@ -149,11 +177,11 @@ describe('count()', () => {
hc.count({ hc.count({
headers: {}, headers: {},
connection: { remoteAddress: 'test2' }, connection: { remoteAddress: 'test2' },
}, '/test/path/2', () => { }, '/test/path/2', false, () => {
hc.count({ hc.count({
headers: {}, headers: {},
connection: { remoteAddress: 'test2' }, connection: { remoteAddress: 'test2' },
}, '/test/path/2', () => { }, '/test/path/2', false, () => {
expect(hincrbyCalls).toEqual([ expect(hincrbyCalls).toEqual([
[ [
'/test/path/2', '/test/path/2',
@@ -195,11 +223,11 @@ describe('count()', () => {
hc.count({ hc.count({
headers: {}, headers: {},
connection: { remoteAddress: 'test3' }, connection: { remoteAddress: 'test3' },
}, '/test/path/3', () => { }, '/test/path/3', false, () => {
hc.count({ hc.count({
headers: {}, headers: {},
connection: { remoteAddress: 'test3' }, connection: { remoteAddress: 'test3' },
}, '/test/path/3', () => { }, '/test/path/3', false, () => {
expect(hincrbyCalls).toEqual([ expect(hincrbyCalls).toEqual([
[ [
'/test/path/3', '/test/path/3',