remove HOSTURL variable and instead get host from header

This commit is contained in:
HF 2020-01-09 15:54:55 +01:00
parent cfbae41817
commit ba144c3b8a
12 changed files with 72 additions and 42 deletions

View File

@ -65,8 +65,6 @@ Configuration takes place in the environment variables that are defined in ecosy
| Variable | Description | Example |
|----------------|:-------------------------|------------------------:|
| HOSTURL | URL of the canvas | "http://localhost" |
| ASSET_SERVER | URL for assets | "http://localhost" |
| PORT | Port | 80 |
| REDIS_URL | URL:PORT of redis server | "http://localhost:6379" |
| MYSQL_HOST | MySql Host | "localhost" |
@ -76,16 +74,18 @@ Configuration takes place in the environment variables that are defined in ecosy
#### Optional Configuration
| Variable | Description | Example |
|-------------------|:--------------------------------------|-------------|
| USE_PROXYCHECK | Check users for Proxies | 0 |
| APISOCKET_KEY | Key for API Socket for SpecialAccess™ | "SDfasife3" |
| ADMIN_IDS | Ids of users with Admin rights | "1,12,3" |
| RECAPTCHA_SECRET | reCaptcha secret key | "asdieewff" |
| RECAPTCHA_SITEKEY | reCaptcha site key | "23ksdfssd" |
| RECAPTCHA_TIME | time in minutes between captchas | 30 |
| SESSION_SECRET | random sting for expression sessions | "ayylmao" |
| LOG_MYSQL | if sql queries should get logged | 0 |
| Variable | Description | Example |
|-------------------|:--------------------------------------|--------------------|
| ASSET_SERVER | URL for assets | "http://localhost" |
| USE_PROXYCHECK | Check users for Proxies | 0 |
| APISOCKET_KEY | Key for API Socket for SpecialAccess™ | "SDfasife3" |
| ADMIN_IDS | Ids of users with Admin rights | "1,12,3" |
| RECAPTCHA_SECRET | reCaptcha secret key | "asdieewff" |
| RECAPTCHA_SITEKEY | reCaptcha site key | "23ksdfssd" |
| RECAPTCHA_TIME | time in minutes between captchas | 30 |
| SESSION_SECRET | random sting for expression sessions | "ayylmao" |
| LOG_MYSQL | if sql queries should get logged | 0 |
| USE_XREALIP | see cloudflare section | 1 |
Notes:
@ -156,10 +156,12 @@ pm2 log flush
pm2 stop web
```
### If using Cloudflare
### If using Cloudflare / Reverse Proxy
In order to get the real IP and not use the cloudflare Proxy IP for placing pixels, we filter those out. The cloudflare IPs are in src/utils/cloudflareip.js and used in src/utils/ip.js. If for some reason cloudflare ads more IPs to it, you can see them at https://www.cloudflare.com/ips/ and add them.
If you use any other Reverse Proxy, you can define it's IPs there too.
If USE\_XREALIP is set, we take the IP from the X-Real-Ip header without checking for cloudflare IPs. Use this if you have pixelplanet running behind nginx use the nginx set\_realip module to give us the client ip on the X-Real-Ip header. And be sure to also forward X-Forwarded-Port and set X-Forwarded-Proto.
### Auto-Start
To have the canvas with all it's components autostart at systemstart,
enable mysql, redis (and probably nginx if you use it) according to your system (`systemctl enable ...`)

View File

@ -7,20 +7,20 @@ import React from 'react';
import ReactDOM from 'react-dom/server';
import Html from './Html';
const RedirectionPage = ({ text }) => (
const RedirectionPage = ({ text, host }) => (
<div>
<h3>{text}</h3>
<p>You will be automatically redirected after 5s</p>
<p>Or <a href="https://pixelplanet.fun">Click here</a> to go back to pixelplanet</p>
<p>Or <a href={host}>Click here</a> to go back to pixelplanet</p>
</div>
);
export function getHtml(description, text) {
export function getHtml(description, text, host) {
const data = {
title: 'PixelPlanet.fun Accounts',
description,
body: <RedirectionPage text={text} />,
code: 'window.setTimeout(function(){window.location.href="https://pixelplanet.fun";},4000)',
body: <RedirectionPage text={text} host ={host} />,
code: `window.setTimeout(function(){window.location.href="${host}";},4000)`,
};
const index = `<!doctype html>${ReactDOM.renderToStaticMarkup(<Html {...data} />)}`;
return index;

View File

@ -7,8 +7,6 @@ if (process.env.BROWSER) {
throw new Error('Do not import `config.js` from inside the client-side code.');
}
export const HOSTURL = process.env.HOSTURL || 'https://pixelplanet.fun';
export const PORT = process.env.PORT || 80;
const TILE_FOLDER_REL = process.env.TILE_FOLDER || 'tiles';
@ -16,6 +14,8 @@ export const TILE_FOLDER = path.join(__dirname, `./${TILE_FOLDER_REL}`);
export const ASSET_SERVER = process.env.ASSET_SERVER || '.';
export const USE_XREALIP = process.env.USE_XREALIP || false;
// Proxycheck
export const USE_PROXYCHECK = parseInt(process.env.USE_PROXYCHECK, 10) || false;

View File

@ -8,7 +8,6 @@ import nodemailer from 'nodemailer';
import logger from './logger';
import { HOUR, MINUTE } from './constants';
import { HOSTURL } from './config';
import { DailyCron, HourlyCron } from '../utils/cron';
import RegUser from '../data/models/RegUser';
@ -37,7 +36,7 @@ class MailProvider {
DailyCron.hook(MailProvider.cleanUsers);
}
sendVerifyMail(to, name) {
sendVerifyMail(to, name, host) {
const pastMail = this.verifyCodes[to];
if (pastMail) {
const minLeft = Math.floor(
@ -53,7 +52,7 @@ class MailProvider {
}
logger.info(`Sending verification mail to ${to} / ${name}`);
const code = this.setCode(to);
const verifyUrl = `${HOSTURL}/api/auth/verify?token=${code}`;
const verifyUrl = `${host}/api/auth/verify?token=${code}`;
transporter.sendMail({
from: 'donotreply@pixelplanet.fun',
to,
@ -70,7 +69,7 @@ class MailProvider {
return null;
}
async sendPasswdResetMail(to, ip) {
async sendPasswdResetMail(to, ip, host) {
const pastMail = this.verifyCodes[to];
if (pastMail) {
if (Date.now() < pastMail.timestamp + 15 * MINUTE) {
@ -100,7 +99,7 @@ class MailProvider {
logger.info(`Sending Password reset mail to ${to}`);
const code = this.setCode(to);
const restoreUrl = `${HOSTURL}/reset_password?token=${code}`;
const restoreUrl = `${host}/reset_password?token=${code}`;
transporter.sendMail({
from: 'donotreply@pixelplanet.fun',
to,

View File

@ -16,7 +16,7 @@ import { sanitizeName } from '../utils/validation';
import logger from './logger';
import { User, RegUser } from '../data/models';
import { auth, HOSTURL } from './config';
import { auth } from './config';
import { compareToHash } from '../utils/hash';
@ -105,7 +105,8 @@ async function oauth_login(email, name, discordid = null) {
*/
passport.use(new FacebookStrategy({
...auth.facebook,
callbackURL: `${HOSTURL}/api/auth/facebook/return`,
callbackURL: `/api/auth/facebook/return`,
proxy: true,
profileFields: ['displayName', 'email'],
}, async (req, accessToken, refreshToken, profile, done) => {
const { displayName: name, emails } = profile;
@ -119,7 +120,8 @@ passport.use(new FacebookStrategy({
*/
passport.use(new DiscordStrategy({
...auth.discord,
callbackURL: `${HOSTURL}/api/auth/discord/return`,
callbackURL: `/api/auth/discord/return`,
proxy: true,
}, async (accessToken, refreshToken, profile, done) => {
// TODO get discord id
console.log({ profile, refreshToken, accessToken });
@ -133,7 +135,8 @@ passport.use(new DiscordStrategy({
*/
passport.use(new GoogleStrategy({
...auth.google,
callbackURL: `${HOSTURL}/api/auth/google/return`,
callbackURL: `/api/auth/google/return`,
proxy: true,
}, async (accessToken, refreshToken, profile, done) => {
const { displayName: name, emails } = profile;
const email = emails[0].value;
@ -146,7 +149,8 @@ passport.use(new GoogleStrategy({
*/
passport.use(new RedditStrategy({
...auth.reddit,
callbackURL: `${HOSTURL}/api/auth/reddit/return`,
callbackURL: `/api/auth/reddit/return`,
proxy: true,
}, async (accessToken, refreshToken, profile, done) => {
console.log({ profile, refreshToken, accessToken });
const redditid = profile.id;
@ -177,7 +181,8 @@ passport.use(new RedditStrategy({
*/
passport.use(new VkontakteStrategy({
...auth.vk,
callbackURL: `${HOSTURL}/api/auth/vk/return`,
callbackURL: `/api/auth/vk/return`,
proxy: true,
scope: ['email'],
profileFields: ['displayName', 'email'],
}, async (accessToken, refreshToken, params, profile, done) => {

View File

@ -8,6 +8,7 @@ import type { Request, Response } from 'express';
import mailProvider from '../../../core/mail';
import { validatePassword, validateEMail } from '../../../utils/validation';
import { getHostFromRequest } from '../../../utils/ip';
import { compareToHash } from '../../../utils/hash';
function validate(email, password) {
@ -55,7 +56,8 @@ export default async (req: Request, res: Response) => {
mailVerified: false,
});
mailProvider.sendVerifyMail(email, user.regUser.name);
const host = getHostFromRequest(req);
mailProvider.sendVerifyMail(email, user.regUser.name, host);
res.json({
success: true,

View File

@ -6,6 +6,7 @@
import express from 'express';
import logger from '../../../core/logger';
import { getHostFromRequest } from '../../../utils/ip';
import register from './register';
import verify from './verify';
@ -67,7 +68,8 @@ export default (passport) => {
res.set({
'Content-Type': 'text/html',
});
const index = getHtml('OAuth Authentification', 'LogIn failed :(, please try again later or register a new account with Mail.');
const host = getHostFromRequest(req);
const index = getHtml('OAuth Authentification', 'LogIn failed :(, please try again later or register a new account with Mail.', host);
res.status(200).send(index);
});

View File

@ -10,6 +10,7 @@ import Sequelize from 'sequelize';
import { RegUser } from '../../../data/models';
import mailProvider from '../../../core/mail';
import getMe from '../../../core/me';
import { getHostFromRequest } from '../../../utils/ip';
import {
validateEMail,
validateName,
@ -73,7 +74,8 @@ export default async (req: Request, res: Response) => {
});
return;
}
mailProvider.sendVerifyMail(email, name);
const host = getHostFromRequest(req);
mailProvider.sendVerifyMail(email, name, host);
res.status(200);
res.json({
success: true,

View File

@ -7,6 +7,7 @@
import type { Request, Response } from 'express';
import mailProvider from '../../../core/mail';
import { getHostFromRequest } from '../../../utils/ip';
export default async (req: Request, res: Response) => {
const { user } = req;
@ -27,7 +28,9 @@ export default async (req: Request, res: Response) => {
return;
}
const error = mailProvider.sendVerifyMail(email, name);
const host = getHostFromRequest(req);
const error = mailProvider.sendVerifyMail(email, name, host);
if (error) {
res.status(400);
res.json({

View File

@ -8,6 +8,7 @@ import type { Request, Response } from 'express';
import mailProvider from '../../../core/mail';
import { validateEMail } from '../../../utils/validation';
import { getHostFromRequest } from '../../../utils/ip';
async function validate(email) {
const errors = [];
@ -29,7 +30,8 @@ export default async (req: Request, res: Response) => {
});
return;
}
const error = await mailProvider.sendPasswdResetMail(email, ip);
const host = getHostFromRequest(req);
const error = await mailProvider.sendPasswdResetMail(email, ip, host);
if (error) {
res.status(400);
res.json({

View File

@ -6,17 +6,19 @@
import type { Request, Response } from 'express';
import { getHtml } from '../../../components/RedirectionPage';
import { getHostFromRequest } from '../../../utils/ip';
import mailProvider from '../../../core/mail';
export default async (req: Request, res: Response) => {
const { token } = req.query;
const success = await mailProvider.verify(token);
const host = getHostFromRequest(req);
if (success) {
const index = getHtml('Mail verification', 'You are now verified :)');
const index = getHtml('Mail verification', 'You are now verified :)', host);
res.status(200).send(index);
} else {
// eslint-disable-next-line max-len
const index = getHtml('Mail verification', 'Your mail verification code is invalid or already expired :(, please request a new one.');
const index = getHtml('Mail verification', 'Your mail verification code is invalid or already expired :(, please request a new one.', host);
res.status(400).send(index);
}
};

View File

@ -7,6 +7,8 @@ import isCloudflareIp from './cloudflareip';
import logger from '../core/logger';
import { USE_XREALIP } from '../core/config';
function isTrustedProxy(ip: string): boolean {
if (ip === '::ffff:127.0.0.1' || ip === '127.0.0.1' || isCloudflareIp(ip)) {
@ -15,15 +17,24 @@ function isTrustedProxy(ip: string): boolean {
return false;
}
/**
* Note: nginx should handle that,
* it's not neccessary to do that ourself
*/
export function getHostFromRequest(req): ?string {
const { headers } = req;
const host = headers['x-forwarded-host'] || headers['host'];
const proto = headers['x-forwarded-proto'] || 'http';
return `${proto}://${host}`;
}
export async function getIPFromRequest(req): ?string {
const { socket, connection, headers } = req;
const conip = (connection ? connection.remoteAddress : socket.remoteAddress);
if (USE_XREALIP) {
const ip = headers['x-real-ip'];
return ip || conip;
}
if (!headers['x-forwarded-for'] || !isTrustedProxy(conip)) {
// eslint-disable-next-line max-len
logger.warn(`Connection not going through nginx and cloudflare! IP: ${conip}`, headers);