Add server package from previous repo

master
Ian Mancini 4 years ago
parent fa9ec31666
commit aa54ffb4f8

@ -1,7 +1,15 @@
{ {
"name": "root", "name": "museo.red",
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"lerna": "^3.22.1" "lerna": "^3.22.1"
},
"scripts": {
"bootstrap": "lerna bootstrap",
"lint": "lerna run lint --stream",
"fix": "lerna run fix --stream",
"start": "lerna run start --stream",
"build": "lerna run build --stream",
"serve": "lerna run serve --stream"
} }
} }

@ -4125,6 +4125,58 @@
"sha.js": "^2.4.8" "sha.js": "^2.4.8"
} }
}, },
"cross-env": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz",
"integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.1"
},
"dependencies": {
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
}
}
},
"cross-spawn": { "cross-spawn": {
"version": "6.0.5", "version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",

@ -17,9 +17,9 @@
"web-vitals": "^0.2.4" "web-vitals": "^0.2.4"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "cross-env HTTPS=true CI=true react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "cross-env CI=true react-scripts test --env=jsdom",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"fix": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix" "fix": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix"
@ -39,6 +39,7 @@
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.6.0", "@typescript-eslint/eslint-plugin": "^4.6.0",
"@typescript-eslint/parser": "^4.6.0", "@typescript-eslint/parser": "^4.6.0",
"cross-env": "^7.0.2",
"eslint": "^7.12.0", "eslint": "^7.12.0",
"eslint-config-prettier": "^6.14.0", "eslint-config-prettier": "^6.14.0",
"eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-jsx-a11y": "^6.4.1",

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}

@ -0,0 +1,18 @@
{
"extends": ["eslint:recommended", "prettier"],
"plugins": ["prettier", "simple-import-sort"],
"rules": {},
"root": true,
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"env": {
"es6": true,
"node": true
},
"rules": {
"prettier/prettier": ["error", {}, { "usePrettierrc": true }],
"simple-import-sort/sort": "error"
}
}

@ -0,0 +1,200 @@
# Created by https://www.toptal.com/developers/gitignore/api/node,vim,emacs,linux
# Edit at https://www.toptal.com/developers/gitignore?templates=node,vim,emacs,linux
### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
dist/
# Flycheck
flycheck_*.el
# projectiles files
.projectile
# directory configuration
.dir-locals.el
# network security
/network-security.data
### Linux ###
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env*.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
### Vim ###
# Swap
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
# End of https://www.toptal.com/developers/gitignore/api/node,vim,emacs,linux
.log/
build/

@ -0,0 +1,7 @@
{
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 90,
"tabWidth": 2
}

@ -0,0 +1,35 @@
version: '3.1'
services:
mongo:
container_name: mongo
image: mongo:4.2.10
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGODB_USER}
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD}
ports:
- 27017:27017
volumes:
- ${DATA_HOME}:/data/db
mongo-express:
container_name: mongo-express
image: mongo-express
restart: always
ports:
- 8181:8081
environment:
ME_CONFIG_MONGODB_SERVER: 'mongo'
ME_CONFIG_MONGODB_ADMINUSERNAME: ${MONGODB_USER}
ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGODB_PASSWORD}
redis:
container_name: redis
image: redis:6.0.8
restart: always
ports:
- 6379:6379
command: >
--requirepass ${REDIS_PASSWORD}
volumes:
- ${DATA_HOME}:/data

@ -0,0 +1,18 @@
MONGODB_PASSWORD=
MONGODB_USER=museum
REDIS_PASSWORD=
SESSION_SECRET=
FACEBOOK_CLIENT_ID=
FACEBOOK_CALLBACK_URL=
FACEBOOK_CLIENT_SECRET=
TWITTER_CONSUMER_KEY=
TWITTER_CONSUMER_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
DATA_HOME=

@ -0,0 +1,12 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "es2020",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"moduleResolution": "node",
"noEmit": true,
"checkJs": true,
"lib": ["dom", "es2017"]
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,50 @@
{
"name": "server",
"version": "0.0.1",
"description": "server for museo.red",
"main": "index.js",
"license": "UNLICENSED",
"scripts": {
"build": "babel src --out-dir build --copy-files",
"serve": "node build/index.js",
"start": "nodemon -w src --exec \"yarn build && yarn serve\"",
"lint": "eslint src/**/*.js*",
"fix": "eslint --fix src/**/*.js*"
},
"author": "Ian Mancini <ianmethyst@gmail.com>",
"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@types/body-parser": "^1.19.0",
"@types/connect-redis": "0.0.14",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.8",
"@types/express-session": "^1.17.0",
"@types/mongoose": "^5.7.36",
"@types/node": "^14.14.3",
"@types/passport": "^1.0.4",
"@types/redis": "^2.8.28",
"eslint": "^7.12.0",
"eslint-config-prettier": "^6.14.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-simple-import-sort": "^5.0.3",
"nodemon": "^2.0.6",
"prettier": "^2.1.2"
},
"dependencies": {
"body-parser": "^1.19.0",
"connect-redis": "^5.0.0",
"cookie-parser": "^1.4.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-session": "^1.17.1",
"mongoose": "^5.10.10",
"passport": "^0.4.1",
"passport-facebook": "^3.0.0",
"passport-google-oauth20": "^2.0.0",
"passport-twitter": "^1.0.4",
"redis": "^3.0.2",
"regenerator-runtime": "^0.13.7"
}
}

@ -0,0 +1,48 @@
#!/bin/sh
check_available() {
# Function to check if a program is installed
which $1 &> /dev/null
if [ $? = 1 ]; then
echo "$1 is not available, please install it before running the script"
exit 1
fi
}
gen_password() {
check_available openssl
openssl rand -base64 32
}
read -p "Redis password: (press enter to randomize): " redis_password
redis_password=${redis_password:-`gen_password`}
read -p "Session secret: (press enter to randomize): " session_secret
session_secret=${session_secret:-`gen_password`}
read -p "MongoDB password: (press enter to randomize): " mongo_password
mongo_password=${mongo_password:-`gen_password`}
if [ ! -f "./.env" ]; then
echo "Copying ./env.example to ./.env"
cp ./env.example ./.env
fi
sed -i -e "s#REDIS_PASSWORD=.*#REDIS_PASSWORD=${redis_password}#g" \
"$(dirname "$0")/.env"
sed -i -e "s#SESSION_SECRET=.*#SESSION_SECRET=${session_secret}#g" \
"$(dirname "$0")/.env"
sed -i -e "s#MONGODB_PASSWORD=.*#MONGODB_PASSWORD=${mongo_password}#g" \
"$(dirname "$0")/.env"
read -p "Start docker containers? (requires docker-compose) [Y/n] " start_docker
start_docker=${start_docker:-Y}
if [[ $start_docker =~ [yY] ]]; then
check_available docker-compose
sudo docker-compose up -d
fi

@ -0,0 +1,9 @@
const ensureAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next()
} else {
return res.redirect('/')
}
}
export default ensureAuthenticated

@ -0,0 +1,32 @@
import dotenv from 'dotenv'
import path from 'path'
dotenv.config({ path: path.join(__dirname, '../../../.env') })
import { Router } from 'express'
import passport from 'passport'
import UserModel from '../models/user'
import { facebookRouter, facebookStrategy } from './providers/facebook'
import { googleRouter, googleStrategy } from './providers/google'
import { twitterRouter, twitterStrategy } from './providers/twitter'
export function initPassport() {
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser((id, done) => {
UserModel.findById(id, (err, user) => {
done(err, user)
})
})
passport.use('facebook', facebookStrategy())
passport.use('twitter', twitterStrategy())
passport.use('google', googleStrategy())
}
export const authRouter = Router()
authRouter.use(facebookRouter)
authRouter.use(twitterRouter)
authRouter.use(googleRouter)

@ -0,0 +1,31 @@
import path from 'path'
import dotenv from 'dotenv'
dotenv.config({ path: path.join(__dirname, '../../../.env') });
import { Strategy } from 'passport-facebook';
import { Router } from 'express'
import passport from 'passport'
import genericStrategy from '../strategy'
const strategyOptions = {
clientID: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
callbackURL: '/auth/facebook/redirect',
profileFields: ['id', 'displayName', 'picture.type(large)', 'email']
}
export function facebookStrategy() {
return new Strategy(strategyOptions, genericStrategy('facebook'));
}
export const facebookRouter = Router()
const facebookAuthenticateOptions = {
authType: 'rerequest', scope: ['email']
}
facebookRouter.get('/facebook', passport.authenticate('facebook', facebookAuthenticateOptions));
facebookRouter.get('/facebook/redirect',
passport.authenticate('facebook', { successRedirect: '/museo', failureRedirect: '/' }));

@ -0,0 +1,26 @@
import { Strategy } from 'passport-google-oauth20';
import { Router } from 'express'
import passport from 'passport'
import genericStrategy from '../strategy'
const strategyOptions = {
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/redirect',
}
export function googleStrategy() {
return new Strategy(strategyOptions, genericStrategy('google'));
}
export const googleRouter = Router()
const googleAuthenticateOptions = {
scope: ['email', 'profile']
}
googleRouter.get('/google', passport.authenticate('google', googleAuthenticateOptions));
googleRouter.get('/google/redirect',
passport.authenticate('google', { successRedirect: '/museo', failureRedirect: '/' }));

@ -0,0 +1,23 @@
import { Strategy } from 'passport-twitter';
import { Router } from 'express'
import passport from 'passport'
import genericStrategy from '../strategy'
const strategyOptions = {
consumerKey: process.env.TWITTER_CONSUMER_KEY,
consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
callbackURL: '/auth/twitter/redirect',
includeEmail: true,
}
export function twitterStrategy() {
return new Strategy(strategyOptions, genericStrategy('twitter'));
}
export const twitterRouter = Router()
twitterRouter.get('/twitter', passport.authenticate('twitter'));
twitterRouter.get('/twitter/redirect',
passport.authenticate('twitter', { successRedirect: '/museo', failureRedirect: '/' }));

@ -0,0 +1,38 @@
import UserModel from '../models/user'
function genericStrategy(provider) {
return async (_accessToken, _refreshToken, profile, done) => {
if (!profile.emails?.[0].value) {
console.error(`${provider} Email permission not provided`)
return done(null, false)
}
try {
const user = await UserModel.findOne({ provider, providerId: profile.id }).exec()
console.info(`${provider} user found. Logging in.`)
if (user) {
return done(null, user)
}
console.info(`${provider} user not found. Creating.`)
const newUser = new UserModel({
providerId: profile.id,
name: profile.displayName,
provider,
email: profile.emails?.[0].value,
photo: profile.photos?.[0].value.replace('_normal', '').replace('=s96-c', ''),
}).save((err) => {
if (err) throw err
})
return done(null, newUser)
} catch (e) {
return done(e)
}
}
}
export default genericStrategy

@ -0,0 +1,80 @@
import 'regenerator-runtime/runtime';
import path from 'path'
import dotenv from 'dotenv'
dotenv.config({ path: path.join(__dirname, '../.env') });
import http from 'http';
import express from 'express';
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import session from 'express-session'
import redis from 'redis'
import connectRedis from 'connect-redis'
import passport from 'passport'
import mongoose from 'mongoose'
import { authRouter, initPassport } from './auth/passport';
import ensureAuthenticated from './auth/middleware';
const RedisStore = connectRedis(session);
const redisClient = redis.createClient({
host: '127.0.0.1',
port: 6379,
password: process.env.REDIS_PASSWORD
})
redisClient.on('error', (error) => {
console.error(error);
});
redisClient.on('connect', () => {
console.log('Connection to Redis has been established successfully.');
});
mongoose.connect('mongodb://localhost:27017', {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
user: process.env.MONGODB_USER,
pass: process.env.MONGODB_PASSWORD,
dbName: 'museum'
}, () => {
console.log('Connection to MongoDB has been established successfully.')
})
const app = express();
app.set('trust proxy', 1);
const server = http.createServer(app);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser(process.env.SESSION_SECRET));
app.use(
session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
})
);
app.use(passport.initialize());
app.use(passport.session());
initPassport();
app.use('/auth', authRouter);
app.use(express.static(path.resolve(__dirname, '../static')));
app.get('/', (_req, res) => {
res.render('index');
});
app.get('/museo', ensureAuthenticated, (req, res) => {
res.render('museo', { user: req.user })
});
server.listen(3000, () => {
console.log('> Ready on http://localhost:3000');
});

@ -0,0 +1,27 @@
import { model, Schema } from 'mongoose'
const userSchema = new Schema(
{
providerId: {
type: String,
required: true,
},
provider: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
photo: String,
},
{ timestamps: true },
)
const UserModel = model('User', userSchema)
export default UserModel
Loading…
Cancel
Save