Add mTLS certificate support
This commit is contained in:
@@ -2,3 +2,4 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
data/*
|
data/*
|
||||||
.env
|
.env
|
||||||
|
certs/*
|
||||||
@@ -34,6 +34,13 @@
|
|||||||
8. Enter the redis url of your e621ng instance. You may need to expose the port from docker manually in development enviornments. This can be done by adding a `ports` mapping to the `redis` service in e621ng's `docker-compose.yml` file. You should map `6379:6379`
|
8. Enter the redis url of your e621ng instance. You may need to expose the port from docker manually in development enviornments. This can be done by adding a `ports` mapping to the `redis` service in e621ng's `docker-compose.yml` file. You should map `6379:6379`
|
||||||
9. Enter your desired port number. It is recommended to leave this at `8000`, if you select anything different you will need to map the correct port in `docker-compose.yml`
|
9. Enter your desired port number. It is recommended to leave this at `8000`, if you select anything different you will need to map the correct port in `docker-compose.yml`
|
||||||
|
|
||||||
|
#### Mutual TLS
|
||||||
|
This is purely for documentation purposes. E621 and this bot on the e621 discord server utilize mTLS to allow the bot to securely ensure that these requests are coming from the bot to allow it to work during DDoS attacks without issue.
|
||||||
|
|
||||||
|
In order to enable this, first create a `certs` directory in the root directory (as in next to the `data` directory). Once this is done, go to cloudflare settings > SSL/TLS > Client Certificates. Click `Add Certificate` in the top right. Follow the directions and use `PEM` key format. Create a `cert.pem` file under `certs` and paste the contents of the `Certificate` into it. Then create a `priv.key` file under `certs` and paste the contents of `Private Key` into it. Continue the setup on cloudflare.
|
||||||
|
|
||||||
|
When done properly the first log the bot will print on start should be `[E621 Requester] Initializing agent with certificates.`
|
||||||
|
|
||||||
### Installing dependencies
|
### Installing dependencies
|
||||||
Run `npm i` to install all node dependencies. This is required to start the bot.
|
Run `npm i` to install all node dependencies. This is required to start the bot.
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
- ./sql:/app/sql
|
- ./sql:/app/sql
|
||||||
|
- ./certs:/app/certs
|
||||||
|
|||||||
+2
-1
@@ -30,6 +30,7 @@
|
|||||||
"build": "npm run clean && node scripts/build.js && npm run copyfiles",
|
"build": "npm run clean && node scripts/build.js && npm run copyfiles",
|
||||||
"clean": "rimraf dist",
|
"clean": "rimraf dist",
|
||||||
"copyfiles": "copyfiles -u 1 \"./src/**/*.html\" ./dist",
|
"copyfiles": "copyfiles -u 1 \"./src/**/*.html\" ./dist",
|
||||||
"encrypt": "node ./scripts/encrypt-data.js"
|
"encrypt": "node ./scripts/encrypt-data.js",
|
||||||
|
"add-author-hash": "node ./scripts/add-author-id-hash.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export class Database {
|
|||||||
|
|
||||||
await Database.db.run(`
|
await Database.db.run(`
|
||||||
INSERT INTO messages (id, id_hash, author_id, author_id_hash, author_name, channel_id, attachments, stickers, content) VALUES
|
INSERT INTO messages (id, id_hash, author_id, author_id_hash, author_name, channel_id, attachments, stickers, content) VALUES
|
||||||
(:id, :id_hash, :author_id, :author_name, :channel_id, :attachments, :stickers, :content)
|
(:id, :id_hash, :author_id, :author_id_hash, :author_name, :channel_id, :attachments, :stickers, :content)
|
||||||
`, ...serializedMessage);
|
`, ...serializedMessage);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+50
-5
@@ -1,5 +1,12 @@
|
|||||||
|
import { existsSync, readFileSync } from 'fs';
|
||||||
import { config } from '../config';
|
import { config } from '../config';
|
||||||
|
import _https from 'https';
|
||||||
|
import _http from 'http';
|
||||||
import { E621Pool, E621Post, E621User, PostFlag, Record } from '../types';
|
import { E621Pool, E621Post, E621User, PostFlag, Record } from '../types';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const secure = config.E621_BASE_URL?.startsWith('https');
|
||||||
|
const http = secure ? _https : _http;
|
||||||
|
|
||||||
const BLACKLISTED_TAGS: string[] = [];
|
const BLACKLISTED_TAGS: string[] = [];
|
||||||
const BLACKLISTED_NONSAFE_TAGS: string[] = ['young'];
|
const BLACKLISTED_NONSAFE_TAGS: string[] = ['young'];
|
||||||
@@ -11,6 +18,16 @@ const USER_AGENT = 'E621DiscordBot';
|
|||||||
|
|
||||||
export const SEARCH_LIMIT = 320;
|
export const SEARCH_LIMIT = 320;
|
||||||
|
|
||||||
|
let agent: _https.Agent | _http.Agent = secure ? new _https.Agent() : new _http.Agent();
|
||||||
|
if (secure && existsSync('./certs/cert.pem') && existsSync('./certs/cert.pem')) {
|
||||||
|
console.log('[E621 Requester] Initializing agent with certificates.');
|
||||||
|
agent = new _https.Agent({
|
||||||
|
cert: readFileSync(path.join(__dirname, '..', '..', 'certs', 'cert.pem'), { encoding: 'utf8' }),
|
||||||
|
key: readFileSync(path.join(__dirname, '..', '..', 'certs', 'priv.key'), { encoding: 'utf8' }),
|
||||||
|
rejectUnauthorized: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function request(path: string, query?: { [name: string]: string }): Promise<any> {
|
async function request(path: string, query?: { [name: string]: string }): Promise<any> {
|
||||||
const url = new URL(config.E621_BASE_URL!);
|
const url = new URL(config.E621_BASE_URL!);
|
||||||
url.pathname = path + '.json';
|
url.pathname = path + '.json';
|
||||||
@@ -21,15 +38,43 @@ async function request(path: string, query?: { [name: string]: string }): Promis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch(url, {
|
return new Promise((resolve) => {
|
||||||
|
http.get(url, {
|
||||||
|
agent,
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': USER_AGENT
|
'User-Agent': USER_AGENT,
|
||||||
|
'Accept': 'application/json'
|
||||||
}
|
}
|
||||||
|
}, (res) => {
|
||||||
|
if (res.statusCode! < 200 || res.statusCode! >= 300) {
|
||||||
|
console.error(`[E621 Requester] Received status code ${res.statusCode} while requesting: ${url}`);
|
||||||
|
res.resume();
|
||||||
|
return resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setEncoding('utf8');
|
||||||
|
|
||||||
|
let data = '';
|
||||||
|
|
||||||
|
res.on('data', (d) => {
|
||||||
|
data += d;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) return null;
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
return await res.json();
|
resolve(JSON.parse(data));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[E621 Requester] Error parsing JSON from:');
|
||||||
|
console.error(data);
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).on('error', (e) => {
|
||||||
|
console.error('[E621 Requester] Error fetching:');
|
||||||
|
console.error(e);
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getE621User(idOrName: string | number): Promise<E621User | null> {
|
export async function getE621User(idOrName: string | number): Promise<E621User | null> {
|
||||||
|
|||||||
Reference in New Issue
Block a user