From 8935ca5c287b7af816dd77b360266769f3403bee Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Sat, 8 Aug 2020 22:29:27 +1000 Subject: [PATCH] Customisable header for IP and country code, and improve how country names are handled --- configs/main.js.example | 6 + helpers/checks/dnsbl.js | 4 +- helpers/countries.js | 10 + helpers/dnsbl.js | 4 +- helpers/processip.js | 4 +- models/forms/makepost.js | 14 +- models/pages/manage/settings.js | 5 +- package-lock.json | 13 ++ package.json | 1 + views/includes/2charisocountries.pug | 262 +-------------------------- 10 files changed, 51 insertions(+), 272 deletions(-) create mode 100644 helpers/countries.js diff --git a/configs/main.js.example b/configs/main.js.example index 8c25b075..d8933570 100644 --- a/configs/main.js.example +++ b/configs/main.js.example @@ -27,6 +27,12 @@ module.exports = { //list of allowed host for checking referrer allowedHosts: ['domain.com', 'www.domain.com'], + //These 2 are usually not necessary to change. Only if you use a proxy/cdn like cloudflare, and then it probably requires change to nginx config. + //header for country codes, for cloudflare, use 'Cf-Ipcountry' + countryCodeHeader: 'x-country-code', + //header for visitor IP, for cloudflare use 'CF-Connecting-IP' + ipHeader: 'X-Real-IP', + //data used in opengraph meta tags. used to generate link previews in e.g. discord, twitter, etc meta: { siteName: 'imageboard', diff --git a/helpers/checks/dnsbl.js b/helpers/checks/dnsbl.js index 88a9a587..c48d444d 100644 --- a/helpers/checks/dnsbl.js +++ b/helpers/checks/dnsbl.js @@ -3,14 +3,14 @@ const cache = require(__dirname+'/../../redis.js') , dynamicResponse = require(__dirname+'/../dynamic.js') , deleteTempFiles = require(__dirname+'/../files/deletetempfiles.js') - , { dnsbl, blockBypass } = require(__dirname+'/../../configs/main.js') + , { ipHeader, dnsbl, blockBypass } = require(__dirname+'/../../configs/main.js') , { batch } = require('dnsbl'); module.exports = async (req, res, next) => { if (dnsbl.enabled && dnsbl.blacklists.length > 0 //if dnsbl enabled and has more than 0 blacklists && (!res.locals.blockBypass || !blockBypass.bypassDnsbl)) { //and there is no valid block bypass, or they do not bypass dnsbl - const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; + const ip = req.headers[ipHeader] || req.connection.remoteAddress; let isBlacklisted = await cache.get(`blacklisted:${ip}`); if (isBlacklisted === null) { //not cached const dnsblResp = await batch(ip, dnsbl.blacklists); diff --git a/helpers/countries.js b/helpers/countries.js new file mode 100644 index 00000000..c6c0575f --- /dev/null +++ b/helpers/countries.js @@ -0,0 +1,10 @@ +'use strict'; + +const countries = require('i18n-iso-countries') + , countryNamesMap = countries.getNames('en') + , countryCodes = Object.keys(countryNamesMap); + +module.exports = { + countryNamesMap, + countryCodes, +} diff --git a/helpers/dnsbl.js b/helpers/dnsbl.js index b525a96a..03851468 100644 --- a/helpers/dnsbl.js +++ b/helpers/dnsbl.js @@ -2,13 +2,13 @@ const cache = require(__dirname+'/../redis.js') , dynamicResponse = require(__dirname+'/dynamic.js') - , { dnsbl } = require(__dirname+'/../configs/main.js') + , { ipHeader, dnsbl } = require(__dirname+'/../configs/main.js') , { batch } = require('dnsbl'); module.exports = async (req, res, next) => { if (dnsbl.enabled) { - const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; + const ip = req.headers[ipHeader] || req.connection.remoteAddress; let isBlacklisted = await cache.get(`blacklisted:${ip}`); if (isBlacklisted === null) { //not cached const dnsblResp = await batch(ip, dnsbl.blacklists); diff --git a/helpers/processip.js b/helpers/processip.js index 97194739..4ee2697f 100644 --- a/helpers/processip.js +++ b/helpers/processip.js @@ -1,11 +1,11 @@ 'use strict'; -const { ipHashPermLevel } = require(__dirname+'/../configs/main.js') +const { ipHeader, ipHashPermLevel } = require(__dirname+'/../configs/main.js') , { isIP } = require('net') , hashIp = require(__dirname+'/haship.js'); module.exports = (req, res, next) => { - const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; //need to consider forwarded-for, etc here and in nginx + const ip = req.headers[ipHeader] || req.connection.remoteAddress; const ipVersion = isIP(ip); if (ipVersion) { const delimiter = ipVersion === 4 ? '.' : ':'; diff --git a/models/forms/makepost.js b/models/forms/makepost.js index bf7c7f59..7e293607 100644 --- a/models/forms/makepost.js +++ b/models/forms/makepost.js @@ -1,6 +1,7 @@ 'use strict'; const path = require('path') + , { countryNamesMap } = require('../../helpers/countries.js') , { createHash, randomBytes } = require('crypto') , { remove, pathExists } = require('fs-extra') , uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js') @@ -22,7 +23,7 @@ const path = require('path') , timeUtils = require(__dirname+'/../../helpers/timeutils.js') , deletePosts = require(__dirname+'/deletepost.js') , spamCheck = require(__dirname+'/../../helpers/checks/spamcheck.js') - , { thumbSize, thumbExtension, postPasswordSecret, strictFiltering } = require(__dirname+'/../../configs/main.js') + , { countryCodeHeader, thumbSize, thumbExtension, postPasswordSecret, strictFiltering } = require(__dirname+'/../../configs/main.js') , buildQueue = require(__dirname+'/../../queue.js') , dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') , { buildThread } = require(__dirname+'/../../helpers/tasks.js'); @@ -50,11 +51,11 @@ module.exports = async (req, res, next) => { captchaMode, lockMode, allowedFileTypes, flags } = res.locals.board.settings; if (flags === true && res.locals.permLevel >= 4 - && req.headers['x-country-code'] - && blockedCountries.includes(req.headers['x-country-code'])) { + && req.headers[countryCodeHeader] + && blockedCountries.includes(req.headers[countryCodeHeader])) { return dynamicResponse(req, res, 403, 'message', { 'title': 'Forbidden', - 'message': `Your country code ${req.headers['x-country-code']} is not allowed to post on this board`, + 'message': `Your country code ${req.headers[countryCodeHeader]} is not allowed to post on this board`, 'redirect': redirect }); } @@ -312,9 +313,10 @@ module.exports = async (req, res, next) => { } let country = null; if (flags === true) { + const code = req.headers[countryCodeHeader]; country = { - 'code': req.headers['x-country-code'], - 'name': req.headers['x-country-name'] + code, + 'name': countryNamesMap[code] } } let password = null; diff --git a/models/pages/manage/settings.js b/models/pages/manage/settings.js index 73cbe8da..afa2a276 100644 --- a/models/pages/manage/settings.js +++ b/models/pages/manage/settings.js @@ -1,6 +1,7 @@ 'use strict'; -const { themes, codeThemes } = require(__dirname+'/../../../helpers/themes.js'); +const { themes, codeThemes } = require(__dirname+'/../../../helpers/themes.js') + , { countryNamesMap, countryCodes } = require(__dirname+'/../../../helpers/countries.js') module.exports = async (req, res, next) => { @@ -8,6 +9,8 @@ module.exports = async (req, res, next) => { .set('Cache-Control', 'private, max-age=5') .render('managesettings', { csrf: req.csrfToken(), + countryNamesMap, + countryCodes, themes, codeThemes, }); diff --git a/package-lock.json b/package-lock.json index 2c583010..79555f73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2006,6 +2006,11 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, + "diacritics": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", + "integrity": "sha1-PvqHMj67hj5mls67AILUj/PW96E=" + }, "dicer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", @@ -3879,6 +3884,14 @@ } } }, + "i18n-iso-countries": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-6.0.0.tgz", + "integrity": "sha512-2YOLRUNrnOq/sVchB6PfOgZ4E0rRMfxxy+QMhjv+2fiJHMidmmmb24UPHwXmzxyybB8mFPU+/uE46ebLOJIrpQ==", + "requires": { + "diacritics": "1.3.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/package.json b/package.json index edde4d46..8c086c5d 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "gulp-pug": "^4.0.1", "gulp-uglify-es": "^2.0.0", "highlight.js": "^10.1.2", + "i18n-iso-countries": "^6.0.0", "ioredis": "^4.14.1", "mongodb": "^3.6.0", "node-fetch": "^2.6.0", diff --git a/views/includes/2charisocountries.pug b/views/includes/2charisocountries.pug index 934a1d65..8086cf22 100644 --- a/views/includes/2charisocountries.pug +++ b/views/includes/2charisocountries.pug @@ -1,264 +1,8 @@ -- - const codeKeys = ['??', 'AD','AE','AF','AG','AI','AL','AM','AO','AQ','AR','AS','AT','AU','AW','AX','AZ','BA','BB','BD','BE','BF','BG','BH','BI','BJ','BL','BM','BN','BO','BQ','BR','BS','BT','BV','BW','BY','BZ','CA','CC','CD','CF','CG','CH','CI','CK','CL','CM','CN','CO','CR','CU','CV','CW','CX','CY','CZ','DE','DJ','DK','DM','DO','DZ','EC','EE','EG','EH','ER','ES','ET','FI','FJ','FK','FM','FO','FR','GA','GB','GD','GE','GF','GG','GH','GI','GL','GM','GN','GP','GQ','GR','GS','GT','GU','GW','GY','HK','HM','HN','HR','HT','HU','ID','IE','IL','IM','IN','IO','IQ','IR','IS','IT','JE','JM','JO','JP','KE','KG','KH','KI','KM','KN','KP','KR','KW','KY','KZ','LA','LB','LC','LI','LK','LR','LS','LT','LU','LV','LY','MA','MC','MD','ME','MF','MG','MH','MK','ML','MM','MN','MO','MP','MQ','MR','MS','MT','MU','MV','MW','MX','MY','MZ','NA','NC','NE','NF','NG','NI','NL','NO','NP','NR','NU','NZ','OM','PA','PE','PF','PG','PH','PK','PL','PM','PN','PR','PS','PT','PW','PY','QA','RE','RO','RS','RU','RW','SA','SB','SC','SD','SE','SG','SH','SI','SJ','SK','SL','SM','SN','SO','SR','SS','ST','SV','SX','SY','SZ','TC','TD','TF','TG','TH','TJ','TK','TL','TM','TN','TO','TR','TT','TV','TW','TZ','UA','UG','UM','US','UY','UZ','VA','VC','VE','VG','VI','VN','VU','WF','WS','XK','YE','YT','ZA','ZM','ZW']; - const codeMap = { - '??': 'TOR (not implemented yet)', - 'AD': 'Andorra', - 'AE': 'United Arab Emirates', - 'AF': 'Afghanistan', - 'AG': 'Antigua and Barbuda', - 'AI': 'Anguilla', - 'AL': 'Albania', - 'AM': 'Armenia', - 'AO': 'Angola', - 'AQ': 'Antarctica', - 'AR': 'Argentina', - 'AS': 'American Samoa', - 'AT': 'Austria', - 'AU': 'Australia', - 'AW': 'Aruba', - 'AX': 'Aland Islands', - 'AZ': 'Azerbaijan', - 'BA': 'Bosnia and Herzegovina', - 'BB': 'Barbados', - 'BD': 'Bangladesh', - 'BE': 'Belgium', - 'BF': 'Burkina Faso', - 'BG': 'Bulgaria', - 'BH': 'Bahrain', - 'BI': 'Burundi', - 'BJ': 'Benin', - 'BL': 'Saint Barthelemy', - 'BM': 'Bermuda', - 'BN': 'Brunei', - 'BO': 'Bolivia', - 'BQ': 'Bonaire, Saint Eustatius and Saba ', - 'BR': 'Brazil', - 'BS': 'Bahamas', - 'BT': 'Bhutan', - 'BV': 'Bouvet Island', - 'BW': 'Botswana', - 'BY': 'Belarus', - 'BZ': 'Belize', - 'CA': 'Canada', - 'CC': 'Cocos Islands', - 'CD': 'Democratic Republic of the Congo', - 'CF': 'Central African Republic', - 'CG': 'Republic of the Congo', - 'CH': 'Switzerland', - 'CI': 'Ivory Coast', - 'CK': 'Cook Islands', - 'CL': 'Chile', - 'CM': 'Cameroon', - 'CN': 'China', - 'CO': 'Colombia', - 'CR': 'Costa Rica', - 'CU': 'Cuba', - 'CV': 'Cape Verde', - 'CW': 'Curacao', - 'CX': 'Christmas Island', - 'CY': 'Cyprus', - 'CZ': 'Czech Republic', - 'DE': 'Germany', - 'DJ': 'Djibouti', - 'DK': 'Denmark', - 'DM': 'Dominica', - 'DO': 'Dominican Republic', - 'DZ': 'Algeria', - 'EC': 'Ecuador', - 'EE': 'Estonia', - 'EG': 'Egypt', - 'EH': 'Western Sahara', - 'ER': 'Eritrea', - 'ES': 'Spain', - 'ET': 'Ethiopia', - 'FI': 'Finland', - 'FJ': 'Fiji', - 'FK': 'Falkland Islands', - 'FM': 'Micronesia', - 'FO': 'Faroe Islands', - 'FR': 'France', - 'GA': 'Gabon', - 'GB': 'United Kingdom', - 'GD': 'Grenada', - 'GE': 'Georgia', - 'GF': 'French Guiana', - 'GG': 'Guernsey', - 'GH': 'Ghana', - 'GI': 'Gibraltar', - 'GL': 'Greenland', - 'GM': 'Gambia', - 'GN': 'Guinea', - 'GP': 'Guadeloupe', - 'GQ': 'Equatorial Guinea', - 'GR': 'Greece', - 'GS': 'South Georgia and the South Sandwich Islands', - 'GT': 'Guatemala', - 'GU': 'Guam', - 'GW': 'Guinea-Bissau', - 'GY': 'Guyana', - 'HK': 'Hong Kong', - 'HM': 'Heard Island and McDonald Islands', - 'HN': 'Honduras', - 'HR': 'Croatia', - 'HT': 'Haiti', - 'HU': 'Hungary', - 'ID': 'Indonesia', - 'IE': 'Ireland', - 'IL': 'Israel', - 'IM': 'Isle of Man', - 'IN': 'India', - 'IO': 'British Indian Ocean Territory', - 'IQ': 'Iraq', - 'IR': 'Iran', - 'IS': 'Iceland', - 'IT': 'Italy', - 'JE': 'Jersey', - 'JM': 'Jamaica', - 'JO': 'Jordan', - 'JP': 'Japan', - 'KE': 'Kenya', - 'KG': 'Kyrgyzstan', - 'KH': 'Cambodia', - 'KI': 'Kiribati', - 'KM': 'Comoros', - 'KN': 'Saint Kitts and Nevis', - 'KP': 'North Korea', - 'KR': 'South Korea', - 'KW': 'Kuwait', - 'KY': 'Cayman Islands', - 'KZ': 'Kazakhstan', - 'LA': 'Laos', - 'LB': 'Lebanon', - 'LC': 'Saint Lucia', - 'LI': 'Liechtenstein', - 'LK': 'Sri Lanka', - 'LR': 'Liberia', - 'LS': 'Lesotho', - 'LT': 'Lithuania', - 'LU': 'Luxembourg', - 'LV': 'Latvia', - 'LY': 'Libya', - 'MA': 'Morocco', - 'MC': 'Monaco', - 'MD': 'Moldova', - 'ME': 'Montenegro', - 'MF': 'Saint Martin', - 'MG': 'Madagascar', - 'MH': 'Marshall Islands', - 'MK': 'Macedonia', - 'ML': 'Mali', - 'MM': 'Myanmar', - 'MN': 'Mongolia', - 'MO': 'Macao', - 'MP': 'Northern Mariana Islands', - 'MQ': 'Martinique', - 'MR': 'Mauritania', - 'MS': 'Montserrat', - 'MT': 'Malta', - 'MU': 'Mauritius', - 'MV': 'Maldives', - 'MW': 'Malawi', - 'MX': 'Mexico', - 'MY': 'Malaysia', - 'MZ': 'Mozambique', - 'NA': 'Namibia', - 'NC': 'New Caledonia', - 'NE': 'Niger', - 'NF': 'Norfolk Island', - 'NG': 'Nigeria', - 'NI': 'Nicaragua', - 'NL': 'Netherlands', - 'NO': 'Norway', - 'NP': 'Nepal', - 'NR': 'Nauru', - 'NU': 'Niue', - 'NZ': 'New Zealand', - 'OM': 'Oman', - 'PA': 'Panama', - 'PE': 'Peru', - 'PF': 'French Polynesia', - 'PG': 'Papua New Guinea', - 'PH': 'Philippines', - 'PK': 'Pakistan', - 'PL': 'Poland', - 'PM': 'Saint Pierre and Miquelon', - 'PN': 'Pitcairn', - 'PR': 'Puerto Rico', - 'PS': 'Palestinian Territory', - 'PT': 'Portugal', - 'PW': 'Palau', - 'PY': 'Paraguay', - 'QA': 'Qatar', - 'RE': 'Reunion', - 'RO': 'Romania', - 'RS': 'Serbia', - 'RU': 'Russia', - 'RW': 'Rwanda', - 'SA': 'Saudi Arabia', - 'SB': 'Solomon Islands', - 'SC': 'Seychelles', - 'SD': 'Sudan', - 'SE': 'Sweden', - 'SG': 'Singapore', - 'SH': 'Saint Helena', - 'SI': 'Slovenia', - 'SJ': 'Svalbard and Jan Mayen', - 'SK': 'Slovakia', - 'SL': 'Sierra Leone', - 'SM': 'San Marino', - 'SN': 'Senegal', - 'SO': 'Somalia', - 'SR': 'Suriname', - 'SS': 'South Sudan', - 'ST': 'Sao Tome and Principe', - 'SV': 'El Salvador', - 'SX': 'Sint Maarten', - 'SY': 'Syria', - 'SZ': 'Swaziland', - 'TC': 'Turks and Caicos Islands', - 'TD': 'Chad', - 'TF': 'French Southern Territories', - 'TG': 'Togo', - 'TH': 'Thailand', - 'TJ': 'Tajikistan', - 'TK': 'Tokelau', - 'TL': 'East Timor', - 'TM': 'Turkmenistan', - 'TN': 'Tunisia', - 'TO': 'Tonga', - 'TR': 'Turkey', - 'TT': 'Trinidad and Tobago', - 'TV': 'Tuvalu', - 'TW': 'Taiwan', - 'TZ': 'Tanzania', - 'UA': 'Ukraine', - 'UG': 'Uganda', - 'UM': 'United States Minor Outlying Islands', - 'US': 'United States', - 'UY': 'Uruguay', - 'UZ': 'Uzbekistan', - 'VA': 'Vatican', - 'VC': 'Saint Vincent and the Grenadines', - 'VE': 'Venezuela', - 'VG': 'British Virgin Islands', - 'VI': 'U.S. Virgin Islands', - 'VN': 'Vietnam', - 'VU': 'Vanuatu', - 'WF': 'Wallis and Futuna', - 'WS': 'Samoa', - 'XK': 'Kosovo', - 'YE': 'Yemen', - 'YT': 'Mayotte', - 'ZA': 'South Africa', - 'ZM': 'Zambia', - 'ZW': 'Zimbabwe' - } - - const blockedCountries = new Set(board.settings.blockedCountries); select(name='countries' size='10' multiple) optgroup(label='Currently blocked') each code in board.settings.blockedCountries - option(value=code selected=true) #{codeMap[code]} + option(value=code selected=true) #{countryNamesMap[code]} optgroup(label='Not blocked') - each code in codeKeys.filter(c => !blockedCountries.has(c)) - option(value=code) #{codeMap[code]} + each code in countryCodes.filter(c => !blockedCountries.has(c)) + option(value=code) #{countryNamesMap[code]}