├── .gitignore ├── config └── flagged-repos.example.json ├── package.json ├── README.md ├── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | config/flagged-repos.json -------------------------------------------------------------------------------- /config/flagged-repos.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "updated": "", 4 | "flaggedRepoURLs": [ 5 | "pirates.com" 6 | ] 7 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flaggedrepoapi", 3 | "version": "1.0.0", 4 | "description": "A simple API written in node to return if a sileo repo is flagged.", 5 | "main": "index.js", 6 | "author": "nullpixel & Sileo Team", 7 | "license": "MIT", 8 | "dependencies": { 9 | "express": "^4.16.4" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Flagged Repo API 4 | 5 | A simple API written in node to return if a Sileo repo is flagged. A production version of this API can be found at [flagged-repo-api.getsileo.app](https://flagged-repo-api.getsileo.app). 6 | 7 | ## Why is my repo flagged? 8 | 9 | If you believe your repo is wrongly flagged, please contact [@SileoSupport](https://twitter.com/SileoSupport) on Twitter. Please do not make a PR to this repo attempting to remove it, as the flagged repo list is not published. 10 | 11 | Additionally, if you wish to report a dangerous repo, please contact [@SileoSupport](https://twitter.com/SileoSupport) on Twitter where the claims will be investigated. Again, do not open a PR on this repo for that reason. 12 | 13 | ## Installation 14 | 15 | ### Flagged Repo "database" 16 | 17 | * For obvious reasons, we do not ship the JSON file containing flagged repos. Therefore, you will have to move `config/flagged-repos.example.json` to `config/flagged-repos.json` and add some sample repos for testing. 18 | * The API normalises the URL, stripping the protocol (http/https), removing any trailing slashes. 19 | 20 | ### Setup 21 | 22 | 1. `yarn install` 23 | 2. Move `config/flagged-repos.example.json` to `config/flagged-repos.json` and add some sample repos for testing 24 | 3. `node index.js` 25 | 4. :tada: 26 | 27 | ## Developers 28 | 29 | Feel free to use our API. It has been optimised for speed, so your traffic should be fine. The two calls it supports are listed below. 30 | 31 | ### GET `/info` 32 | 33 | Returns information about the database that the API is currently using, such as when it was last updated and how many repos are flagged. 34 | 35 | **Example response:** 36 | 37 | ```json 38 | {"version":1,"updated":"2018-12-27T14:36:35.828Z","flagged_count":44} 39 | ``` 40 | 41 | ### POST `/flagged` 42 | 43 | Returns `true` if the repo is flagged, `false` if it's not. 44 | 45 | **Example request:** 46 | 47 | **Content-Type:** `application/json` 48 | ```json 49 | {"url": "https://pirates.com"} 50 | ``` 51 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { parse } = require("url"); 2 | const express = require("express"); 3 | const app = express(); 4 | 5 | const repolist = require("./config/flagged-repos.json"); 6 | const flaggedRepos = repolist.flaggedRepoURLs; 7 | 8 | var repoRegexes = []; 9 | 10 | const createRegex = (url) => { 11 | // basically https://stackoverflow.com/a/39095107/9784092 but better 12 | const split = /([^\/]+)(\/.*)?/; 13 | 14 | const matches = url.match(split); 15 | if (!matches) return null; 16 | 17 | var preparedURL = ""; 18 | preparedURL = `${matches[1]}`.replace(/[?()[\]\\.+^$|]/g, "\\$&").replace(/\*\\./g,'(?:[^/]*\\.)*').replace(/\*$/,'[^/]*'); 19 | 20 | if (matches[2]) { 21 | preparedURL += matches[2].replace(/[?()[\]\\.+^$|]/g, "\\$&").replace(/\/\*(?=$|\/)/g, '(?:/[^]*)?'); 22 | } 23 | return new RegExp(`^${preparedURL}$`, "i"); 24 | } 25 | 26 | const regenerateRegex = () => { 27 | console.log("Generating regex array."); 28 | for (const repo of flaggedRepos) { 29 | const regex = createRegex(repo); 30 | if (!regex) return console.error(`Failed to generate regex for ${repo}.`); 31 | 32 | repoRegexes.push(regex); 33 | } 34 | console.log("Generated regex array."); 35 | } 36 | 37 | app.use(express.json()); 38 | 39 | app.get("/", (_, res) => { 40 | return res.redirect("https://github.com/SileoApp/FlaggedRepoAPI"); 41 | }); 42 | 43 | app.get("/info", (_, res) => { 44 | return res.json({ 45 | version: repolist.version, 46 | updated: repolist.updated, 47 | flagged_count: repolist.flaggedRepoURLs.length 48 | }); 49 | }); 50 | 51 | app.post("/flagged", (req, res) => { 52 | if (!req.body.url) return res.sendStatus(400); 53 | 54 | const parsed = parse(req.body.url); 55 | const normalised = `${parsed.hostname}${parsed.pathname == "/" ? "" : parsed.pathname}`.replace(/^www\./,'').trim(); 56 | 57 | const hasFlagged = repoRegexes.some(regex => { 58 | return normalised.match(regex) !== null; 59 | }); 60 | 61 | return res.send(hasFlagged); 62 | }); 63 | 64 | regenerateRegex(); 65 | const port = process.env.PORT || 3000; 66 | app.listen(port, () => console.log(`Flagged Repo API listening on http://localhost:${port}.`)); -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.5: 6 | version "1.3.5" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" 8 | dependencies: 9 | mime-types "~2.1.18" 10 | negotiator "0.6.1" 11 | 12 | array-flatten@1.1.1: 13 | version "1.1.1" 14 | resolved "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 15 | 16 | body-parser@1.18.3: 17 | version "1.18.3" 18 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" 19 | dependencies: 20 | bytes "3.0.0" 21 | content-type "~1.0.4" 22 | debug "2.6.9" 23 | depd "~1.1.2" 24 | http-errors "~1.6.3" 25 | iconv-lite "0.4.23" 26 | on-finished "~2.3.0" 27 | qs "6.5.2" 28 | raw-body "2.3.3" 29 | type-is "~1.6.16" 30 | 31 | bytes@3.0.0: 32 | version "3.0.0" 33 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 34 | 35 | content-disposition@0.5.2: 36 | version "0.5.2" 37 | resolved "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 38 | 39 | content-type@~1.0.4: 40 | version "1.0.4" 41 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 42 | 43 | cookie-signature@1.0.6: 44 | version "1.0.6" 45 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 46 | 47 | cookie@0.3.1: 48 | version "0.3.1" 49 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 50 | 51 | debug@2.6.9: 52 | version "2.6.9" 53 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 54 | dependencies: 55 | ms "2.0.0" 56 | 57 | depd@~1.1.2: 58 | version "1.1.2" 59 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 60 | 61 | destroy@~1.0.4: 62 | version "1.0.4" 63 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 64 | 65 | ee-first@1.1.1: 66 | version "1.1.1" 67 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 68 | 69 | encodeurl@~1.0.2: 70 | version "1.0.2" 71 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 72 | 73 | escape-html@~1.0.3: 74 | version "1.0.3" 75 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 76 | 77 | etag@~1.8.1: 78 | version "1.8.1" 79 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 80 | 81 | express@^4.16.4: 82 | version "4.16.4" 83 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" 84 | dependencies: 85 | accepts "~1.3.5" 86 | array-flatten "1.1.1" 87 | body-parser "1.18.3" 88 | content-disposition "0.5.2" 89 | content-type "~1.0.4" 90 | cookie "0.3.1" 91 | cookie-signature "1.0.6" 92 | debug "2.6.9" 93 | depd "~1.1.2" 94 | encodeurl "~1.0.2" 95 | escape-html "~1.0.3" 96 | etag "~1.8.1" 97 | finalhandler "1.1.1" 98 | fresh "0.5.2" 99 | merge-descriptors "1.0.1" 100 | methods "~1.1.2" 101 | on-finished "~2.3.0" 102 | parseurl "~1.3.2" 103 | path-to-regexp "0.1.7" 104 | proxy-addr "~2.0.4" 105 | qs "6.5.2" 106 | range-parser "~1.2.0" 107 | safe-buffer "5.1.2" 108 | send "0.16.2" 109 | serve-static "1.13.2" 110 | setprototypeof "1.1.0" 111 | statuses "~1.4.0" 112 | type-is "~1.6.16" 113 | utils-merge "1.0.1" 114 | vary "~1.1.2" 115 | 116 | finalhandler@1.1.1: 117 | version "1.1.1" 118 | resolved "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" 119 | dependencies: 120 | debug "2.6.9" 121 | encodeurl "~1.0.2" 122 | escape-html "~1.0.3" 123 | on-finished "~2.3.0" 124 | parseurl "~1.3.2" 125 | statuses "~1.4.0" 126 | unpipe "~1.0.0" 127 | 128 | forwarded@~0.1.2: 129 | version "0.1.2" 130 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 131 | 132 | fresh@0.5.2: 133 | version "0.5.2" 134 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 135 | 136 | http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: 137 | version "1.6.3" 138 | resolved "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" 139 | dependencies: 140 | depd "~1.1.2" 141 | inherits "2.0.3" 142 | setprototypeof "1.1.0" 143 | statuses ">= 1.4.0 < 2" 144 | 145 | iconv-lite@0.4.23: 146 | version "0.4.23" 147 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" 148 | dependencies: 149 | safer-buffer ">= 2.1.2 < 3" 150 | 151 | inherits@2.0.3: 152 | version "2.0.3" 153 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 154 | 155 | ipaddr.js@1.8.0: 156 | version "1.8.0" 157 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" 158 | 159 | media-typer@0.3.0: 160 | version "0.3.0" 161 | resolved "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 162 | 163 | merge-descriptors@1.0.1: 164 | version "1.0.1" 165 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 166 | 167 | methods@~1.1.2: 168 | version "1.1.2" 169 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 170 | 171 | mime-db@~1.37.0: 172 | version "1.37.0" 173 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" 174 | 175 | mime-types@~2.1.18: 176 | version "2.1.21" 177 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" 178 | dependencies: 179 | mime-db "~1.37.0" 180 | 181 | mime@1.4.1: 182 | version "1.4.1" 183 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" 184 | 185 | ms@2.0.0: 186 | version "2.0.0" 187 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 188 | 189 | negotiator@0.6.1: 190 | version "0.6.1" 191 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 192 | 193 | on-finished@~2.3.0: 194 | version "2.3.0" 195 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 196 | dependencies: 197 | ee-first "1.1.1" 198 | 199 | parseurl@~1.3.2: 200 | version "1.3.2" 201 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" 202 | 203 | path-to-regexp@0.1.7: 204 | version "0.1.7" 205 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 206 | 207 | proxy-addr@~2.0.4: 208 | version "2.0.4" 209 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" 210 | dependencies: 211 | forwarded "~0.1.2" 212 | ipaddr.js "1.8.0" 213 | 214 | qs@6.5.2: 215 | version "6.5.2" 216 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 217 | 218 | range-parser@~1.2.0: 219 | version "1.2.0" 220 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 221 | 222 | raw-body@2.3.3: 223 | version "2.3.3" 224 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" 225 | dependencies: 226 | bytes "3.0.0" 227 | http-errors "1.6.3" 228 | iconv-lite "0.4.23" 229 | unpipe "1.0.0" 230 | 231 | safe-buffer@5.1.2: 232 | version "5.1.2" 233 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 234 | 235 | "safer-buffer@>= 2.1.2 < 3": 236 | version "2.1.2" 237 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 238 | 239 | send@0.16.2: 240 | version "0.16.2" 241 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" 242 | dependencies: 243 | debug "2.6.9" 244 | depd "~1.1.2" 245 | destroy "~1.0.4" 246 | encodeurl "~1.0.2" 247 | escape-html "~1.0.3" 248 | etag "~1.8.1" 249 | fresh "0.5.2" 250 | http-errors "~1.6.2" 251 | mime "1.4.1" 252 | ms "2.0.0" 253 | on-finished "~2.3.0" 254 | range-parser "~1.2.0" 255 | statuses "~1.4.0" 256 | 257 | serve-static@1.13.2: 258 | version "1.13.2" 259 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" 260 | dependencies: 261 | encodeurl "~1.0.2" 262 | escape-html "~1.0.3" 263 | parseurl "~1.3.2" 264 | send "0.16.2" 265 | 266 | setprototypeof@1.1.0: 267 | version "1.1.0" 268 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 269 | 270 | "statuses@>= 1.4.0 < 2": 271 | version "1.5.0" 272 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 273 | 274 | statuses@~1.4.0: 275 | version "1.4.0" 276 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" 277 | 278 | type-is@~1.6.16: 279 | version "1.6.16" 280 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" 281 | dependencies: 282 | media-typer "0.3.0" 283 | mime-types "~2.1.18" 284 | 285 | unpipe@1.0.0, unpipe@~1.0.0: 286 | version "1.0.0" 287 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 288 | 289 | utils-merge@1.0.1: 290 | version "1.0.1" 291 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 292 | 293 | vary@~1.1.2: 294 | version "1.1.2" 295 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 296 | --------------------------------------------------------------------------------