diff --git a/README.md b/README.md index cdfc48b..b449e29 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,29 @@ Icy Network Primary Web Application - Authentication and News ## About Icy Network Icy Network is a community network aimed at anyone who likes friendly discussions and playing multiplayer games, such as Minecraft. -### Currently IcyNet-owned community platforms +### Currently IcyNet-managed community platforms * mc.icynet.eu - Minecraft Server * [Discord server](https://discord.gg/Xe7MKSx) * icynet.ml - IRC Network +More to come! + ## The Goal of this Application -To create a central news outlet and APIs for all of Icy Network-owned community platforms. -This application will also include authentication services such as OAuth2 in order to unite our websites with a single login. +This application is used for authentication services such as OAuth2 in order to unite our websites with a single login and as a centeral news outlet for Icy Network services. + +## Setup +The first time you run the application, it will migrate the database and that may take a while. +### Development +Clone this repository and then + +1. `npm install` to get all the packages +2. `cp config.example.toml config.toml` copy the configuration +3. `npm run watch` to run the style and front-end script building watch task +4. `npm start -- -d` to start the application in development mode + +There is also a watch mode for the server. To enable `server` file tree watching you must provide both `-d` and `-w` as parameters. This task will reset all workers when any file in the `server` directory changes, enabling for live debugging. + +### Production + +1. `npm run build` +2. `npm start` diff --git a/config.example.toml b/config.example.toml new file mode 100644 index 0000000..01ec759 --- /dev/null +++ b/config.example.toml @@ -0,0 +1,77 @@ +# Server configuration +[server] + # Port the server will run on + port=8282 + # Session key + session_key="Session" + # Session secret + session_secret="hackmysessions" + # Number of worker processes (0 to use all CPU cores) + workers=1 + # Domain of this application + domain="http://localhost:8282" + +# Database +# Available database clients: mysql / postgresql(pg) / sqlite3 / oracle / mssql +[database] + client="mysql" + + # Here you will define database connection related to the client + [database.connection] + user="root" + host="localhost" + password="" + database="icynet" + # More information on database configuration can be found here: + # http://knexjs.org/#Installation-client + +# OAuth2 related configuration +[oauth2] + # Byte length of a token + token_length=16 + # 1 week of token life + access_token_life=604800 + # Authorization code life + code_life=3600 + # Whether or not an OAuth2 client authorization decision will be saved + # which means that the user will not be asked for authorization again + # Decisions can be revoked from the user settings page + save_decision=true + +# Redis is currently used for storing sessions +[redis] + port=6379 + +# Uncomment if you want to be using Twitter authentication +[twitter] +# api="" +# api_secret="" + +# Uncomment if you want to be using Facebook authentication +[facebook] +# client="" + +# Uncomment if you want to be using Discord authentication +[discord] +# api="" +# api_secret="" + +# reCAPTCHA configuration +[security] + [security.recaptcha] +# site_key="" +# secret_key="" + +# Email SMTP transport configuration +[email] + enabled=false + admin="icynet@example.com" + [email.transport] + host="mail.example.com" + port=587 + secure=false + [email.transport.auth] + user="" + pass="" + [email.transport.tls] + rejectUnauthorized=false diff --git a/package-lock.json b/package-lock.json index 5c9f375..567cce2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2034,6 +2034,15 @@ "create-hash": "1.1.3" } }, + "exec-sh": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", + "integrity": "sha1-FPdd4/INKG75MwmbLOUKkDWc7xA=", + "dev": true, + "requires": { + "merge": "1.2.0" + } + }, "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", @@ -3380,6 +3389,12 @@ "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.3.tgz", "integrity": "sha1-4gD/TdgjcX+OBWOzLj9UgfyiYrI=" }, + "merge": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", + "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", + "dev": true + }, "merge-descriptors": { "version": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" @@ -5498,6 +5513,24 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, + "watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=", + "dev": true, + "requires": { + "exec-sh": "0.2.0", + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "watchify": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz", diff --git a/package.json b/package.json index d9fe031..ec738cd 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "jquery": "^3.2.1", "standard": "^10.0.3", "uglify-js": "^1.3.5", + "watch": "^1.0.2", "watchify": "^3.9.0" }, "standard": { diff --git a/server/api/oauth2/model.js b/server/api/oauth2/model.js index ab51094..1eb06ba 100644 --- a/server/api/oauth2/model.js +++ b/server/api/oauth2/model.js @@ -239,6 +239,7 @@ const OAuthDB = { return correct }, allowClient: async (userId, clientId, scope) => { + if (!config.oauth2.save_decision) return true if (typeof scope === 'object') { scope = scope.join(' ') } diff --git a/server/index.js b/server/index.js index 152c2e6..544bcfd 100644 --- a/server/index.js +++ b/server/index.js @@ -13,6 +13,15 @@ const args = { port: config.server.port } +function spawnWorkers () { + let workerCount = config.server.workers === 0 ? cpuCount : config.server.workers + console.log('Spinning up ' + workerCount + ' worker process' + (workerCount !== 1 ? 'es' : '')) + + for (let i = 0; i < workerCount; i++) { + spawnWorker() + } +} + async function initialize () { try { const knex = require('knex')(require('../knexfile')) @@ -24,14 +33,33 @@ async function initialize () { console.error('Database error:', err) } - let workerCount = config.server.workers === 0 ? cpuCount : config.server.workers - console.log('Spinning up ' + workerCount + ' worker process' + (workerCount !== 1 ? 'es' : '')) - - for (let i = 0; i < workerCount; i++) { - spawnWorker() + spawnWorkers() + if (args.dev) { + watchFileTree() } } +function watchFileTree () { + if (process.argv.indexOf('-w') === -1) return + console.log('[WatchTask] Starting watcher') + + const watch = require('watch') + watch.watchTree(__dirname, (f, curr, prev) => { + if (typeof f === 'object' && prev === null && curr === null) { + console.log('[WatchTask] Watching %d files', Object.keys(f).length) + return + } + + console.log('[WatchTask] %s changed, restarting workers', f) + if (workers.length) { + for (let i in workers) { + workers[i].send('stop') + } + } + spawnWorkers() + }) +} + function spawnWorker (oldWorker) { const w = cluster.fork() w.process.stdout.on('data', (data) => {