├── .gitignore ├── .vscode └── launch.json ├── README.md ├── apps └── next │ ├── .gitignore │ ├── README.md │ ├── components │ ├── code-with-codemirror.js │ ├── code-with-monaco.js │ ├── hello-world-map.js │ └── nav.js │ ├── config │ └── examples.js │ ├── next.config.js │ ├── package.json │ ├── pages │ ├── codemirror.js │ ├── index.js │ ├── leaflet.js │ ├── monaco-other-page.js │ └── monaco.js │ ├── server.js │ ├── static │ └── favicon.ico │ └── yarn.lock ├── docs ├── codemirror-with-next.md ├── leaflet-with-next.md └── monaco-editor-with-next.md ├── github-oauth-with-hapi-v16 ├── README.md ├── package-lock.json ├── package.json └── server.js ├── github-oauth-with-hapi-v17 ├── README.md ├── package-lock.json ├── package.json └── server.js ├── gitlab-oauth-with-hapi-v16 ├── README.md ├── package-lock.json ├── package.json └── server.js ├── matrix-incoming-webhook ├── README.md ├── index.js ├── package-lock.json └── package.json ├── openwhisk └── README.md └── rocketchat-webhook ├── README.md ├── index.js ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "attach", 10 | "name": "Attach", 11 | "port": 9229 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # snippets 2 | 3 | snippets for building API integrations 4 | 5 | ## Frontend 6 | 7 | ### Maps 8 | 9 | - [Leaflet with Next and OpenStreetMaps](https://github.com/resources/snippets/blob/master/docs/leaflet-with-next.md) 10 | 11 | ### Code Editing 12 | 13 | - [CodeMirror with Next](https://github.com/resources/snippets/blob/master/docs/codemirror-with-next.md) 14 | - [Monaco Editor with Next](https://github.com/resources/snippets/blob/master/docs/monaco-editor-with-next.md) 15 | 16 | ## Backend 17 | 18 | ### Authentication 19 | 20 | #### Hapi.js 21 | 22 | - [GitHub OAuth with Hapi v16](https://github.com/resources/snippets/blob/master/github-oauth-with-hapi-v16) 23 | - [GitLab Oauth with Hapi v16](https://github.com/resources/snippets/blob/master/gitlab-oauth-with-hapi-v16) 24 | 25 | ### Chat 26 | 27 | - [RocketChat Webhook](https://github.com/resources/snippets/blob/master/rocketchat-webhook) 28 | - [Matrix Incoming Webhook](https://github.com/resources/snippets/blob/master/matrix-incoming-webhook) 29 | 30 | ### Functions 31 | 32 | - [OpenWhisk](https://github.com/resources/snippets/blob/master/openwhisk) 33 | -------------------------------------------------------------------------------- /apps/next/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /dist 12 | /.next 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | -------------------------------------------------------------------------------- /apps/next/README.md: -------------------------------------------------------------------------------- 1 | # Next.js frontend app for running code snippets 2 | 3 | ## running 4 | 5 | ``` bash 6 | npm install 7 | npm run dev 8 | ``` 9 | -------------------------------------------------------------------------------- /apps/next/components/code-with-codemirror.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import {UnControlled as CodeMirror} from 'react-codemirror2' 3 | import 'codemirror/mode/javascript/javascript' 4 | import 'codemirror/lib/codemirror.css' 5 | import 'codemirror/theme/material.css' 6 | 7 | export default (props) => ( 8 |
9 | null} 14 | /> 15 |
16 | ) -------------------------------------------------------------------------------- /apps/next/components/code-with-monaco.js: -------------------------------------------------------------------------------- 1 | window.MonacoEnvironment = { baseUrl: '/monaco-editor-external' }; 2 | import * as monaco from '@timkendrick/monaco-editor/dist/external' 3 | import React, { Component } from 'react' 4 | import MonacoEditor from 'react-monaco-editor' 5 | import '../node_modules/@timkendrick/monaco-editor/dist/external/monaco.css' 6 | 7 | export default (props) => ( 8 | null} 16 | editorDidMount={() => null} 17 | {...props} 18 | /> 19 | ) -------------------------------------------------------------------------------- /apps/next/components/hello-world-map.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import {Map, TileLayer, Marker, Popup} from 'react-leaflet' 3 | 4 | export default class HelloWorldMap extends Component { 5 | render() { 6 | return ( 7 |
8 | 9 | OpenStreetMap contributors'} 11 | url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" 12 | /> 13 | 14 | 15 | Hello World 16 | 17 | 18 | 19 | 27 |
28 | ) 29 | } 30 | } -------------------------------------------------------------------------------- /apps/next/components/nav.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import examples from '../config/examples' 3 | 4 | export default () => ( 5 |
6 | Home 7 | 22 |
23 | ) -------------------------------------------------------------------------------- /apps/next/config/examples.js: -------------------------------------------------------------------------------- 1 | export default ( 2 | [ 3 | { 4 | title: "Leaflet", 5 | url: "/leaflet" 6 | }, 7 | { 8 | title: "CodeMirror", 9 | url: "/codemirror" 10 | }, 11 | { 12 | title: "Monaco Editor", 13 | url: "/monaco" 14 | } 15 | ] 16 | ) -------------------------------------------------------------------------------- /apps/next/next.config.js: -------------------------------------------------------------------------------- 1 | const withCSS = require('@zeit/next-css') 2 | module.exports = withCSS({ 3 | webpack: (config) => { 4 | // Fixes npm packages that depend on `fs` module 5 | config.node = { 6 | fs: 'empty' 7 | } 8 | 9 | return config 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /apps/next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@resources/snippets-next", 3 | "private": true, 4 | "scripts": { 5 | "dev": "node server.js", 6 | "build": "next build", 7 | "start": "NODE_ENV=production node server.js" 8 | }, 9 | "dependencies": { 10 | "@timkendrick/monaco-editor": "0.0.7", 11 | "@zeit/next-css": "^0.0.7", 12 | "codemirror": "^5.33.0", 13 | "css-loader": "^0.28.9", 14 | "express": "^4.16.2", 15 | "leaflet": "^1.2.0", 16 | "next": "^5.0.0", 17 | "prop-types": "^15.6.0", 18 | "react": "^16.2.0", 19 | "react-codemirror2": "^3.0.7", 20 | "react-dom": "^16.2.0", 21 | "react-leaflet": "^1.7.8", 22 | "react-monaco-editor": "^0.13.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /apps/next/pages/codemirror.js: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic' 2 | const CodeWithCodemirror = dynamic(import('../components/code-with-codemirror'), {ssr: false}) 3 | import Nav from '../components/nav' 4 | 5 | export default () => { 6 | return ( 7 |
8 | 9 |
11 | ) 12 | } -------------------------------------------------------------------------------- /apps/next/pages/index.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import examples from '../config/examples' 3 | 4 | export default () => ( 5 |
6 |

⬇️ ⬇️ ⬇️

7 |
8 |
9 | { 10 | examples.map((example, ix) => ( 11 | {ix ? ' • ' : ' '}{example.title} 12 | )) 13 | } 14 |
15 | 28 |
29 |
30 | ) -------------------------------------------------------------------------------- /apps/next/pages/leaflet.js: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic' 2 | import NextHead from 'next/head' 3 | const HelloWorldMap = dynamic(import('../components/hello-world-map'), {ssr: false}) 4 | import Nav from '../components/nav' 5 | 6 | export default () => { 7 | return ( 8 |
9 | 10 | 13 | 14 |
17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /apps/next/pages/monaco-other-page.js: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic' 2 | const CodeWithMonaco = dynamic(import('../components/code-with-monaco'), {ssr: false}) 3 | import Link from 'next/link' 4 | import Nav from '../components/nav' 5 | 6 | export default () => { 7 | const someCss = [ 8 | '.exampleDiv {', 9 | ' background-color: #003;', 10 | ' color: #ccc;', 11 | '}' 12 | ].join("\n") 13 | const someJs = [ 14 | "import {myCoolFunc} from './utils'", 15 | 'export default async () => {', 16 | ' await myCoolFunc()', 17 | '}' 18 | ].join("\n") 19 | return ( 20 |
21 |
22 | Home 23 |
24 | 25 | 26 |
28 | ) 29 | } -------------------------------------------------------------------------------- /apps/next/pages/monaco.js: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic' 2 | const CodeWithMonaco = dynamic(import('../components/code-with-monaco'), {ssr: false}) 3 | import Link from 'next/link' 4 | import Nav from '../components/nav' 5 | 6 | export default () => { 7 | const someJs = [ 8 | "import {myCoolFunc} from './utils'", 9 | 'export default async () => {', 10 | ' await myCoolFunc()', 11 | '}' 12 | ].join("\n") 13 | return ( 14 |
15 |
16 | Other Page 17 |
18 | 19 |
21 | ) 22 | } -------------------------------------------------------------------------------- /apps/next/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const next = require('next') 3 | 4 | const port = parseInt(process.env.PORT, 10) || 3000 5 | const dev = process.env.NODE_ENV !== 'production' 6 | const app = next({ dev }) 7 | const handle = app.getRequestHandler() 8 | 9 | app.prepare() 10 | .then(() => { 11 | const server = express() 12 | 13 | server.use( 14 | '/monaco-editor-external', 15 | express.static(`${__dirname}/node_modules/@timkendrick/monaco-editor/dist/external`) 16 | ) 17 | 18 | server.get('*', (req, res) => { 19 | return handle(req, res) 20 | }) 21 | 22 | server.listen(port, err => { 23 | if (err) throw err 24 | console.log(`> Ready on http://localhost:${port}`) 25 | }) 26 | }) -------------------------------------------------------------------------------- /apps/next/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ResourcesCo/snippets/9ee88e798c7d4f19b9782391e16b115a8eb531cc/apps/next/static/favicon.ico -------------------------------------------------------------------------------- /docs/codemirror-with-next.md: -------------------------------------------------------------------------------- 1 | # CodeMirror with Next 2 | 3 | [![live demo](https://img.shields.io/badge/live-demo-green.svg?style=plastic)](https://resourcessnippets-next.now.sh/codemirror) 4 | 5 | ## create & configure the app 6 | 7 | Create the app: 8 | 9 | ``` bash 10 | create-next-app myapp 11 | ``` 12 | 13 | Install the CodeMirror dependencies: 14 | 15 | ``` bash 16 | npm install react-codemirror2 codemirror @zeit/next-css css-loader --save 17 | ``` 18 | 19 | ## add the component 20 | 21 | [components/code-with-codemirror.js](https://github.com/resources/snippets/blob/master/apps/next/components/code-with-codemirror.js) 22 | 23 | ``` jsx 24 | import React, { Component } from 'react' 25 | import {UnControlled as CodeMirror} from 'react-codemirror2' 26 | import 'codemirror/mode/javascript/javascript' 27 | import 'codemirror/lib/codemirror.css' 28 | import 'codemirror/theme/material.css' 29 | 30 | export default (props) => ( 31 |
32 | null} 37 | /> 38 |
39 | ) 40 | ``` 41 | 42 | ## Set up the CSS loader for webpack 43 | 44 | [next.config.js](https://github.com/resources/snippets/blob/master/apps/next/next.config.js) 45 | 46 | ``` js 47 | const withCSS = require('@zeit/next-css') 48 | module.exports = withCSS({ 49 | webpack: (config) => { 50 | // Fixes npm packages that depend on `fs` module 51 | config.node = { 52 | fs: 'empty' 53 | } 54 | 55 | return config 56 | } 57 | }) 58 | ``` 59 | 60 | ## add the component to a page 61 | 62 | To use this component, use a dynamic import with `ssr` set to `false`: 63 | 64 | [pages/codemirror.js](https://github.com/resources/snippets/blob/master/apps/next/pages/codemirror.js) 65 | 66 | ``` jsx 67 | import dynamic from 'next/dynamic' 68 | const CodeWithCodemirror = dynamic(import('../components/code-with-codemirror'), {ssr: false}) 69 | 70 | export default () => { 71 | return ( 72 |
73 | 74 |
75 | ) 76 | } 77 | ``` 78 | -------------------------------------------------------------------------------- /docs/leaflet-with-next.md: -------------------------------------------------------------------------------- 1 | # Leaflet with Next 2 | 3 | [![live demo](https://img.shields.io/badge/live-demo-green.svg?style=plastic)](https://resourcessnippets-next.now.sh/leaflet) 4 | 5 | ## create & configure the app 6 | 7 | Create a next app: 8 | 9 | ``` bash 10 | create-next-app myapp 11 | ``` 12 | 13 | Install the dependencies: 14 | 15 | ``` bash 16 | npm install react-leaflet leaflet prop-types --save 17 | ``` 18 | 19 | ## add the component 20 | 21 | [components/hello-world-map.js](https://github.com/resources/snippets/blob/master/apps/next/components/hello-world-map.js) 22 | 23 | ``` jsx 24 | import React, { Component } from 'react' 25 | import {Map, TileLayer, Marker, Popup} from 'react-leaflet' 26 | 27 | export default class HelloWorldMap extends Component { 28 | render() { 29 | return ( 30 |
31 | 32 | OpenStreetMap contributors'} 34 | url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" 35 | /> 36 | 37 | 38 | Hello World 39 | 40 | 41 | 42 | 50 |
51 | ) 52 | } 53 | } 54 | ``` 55 | 56 | Add a page that uses the component. 57 | 58 | This uses a custom stylesheet and a dynamic import with `ssr` set to `false`. 59 | 60 | [pages/leaflet.js](https://github.com/resources/snippets/blob/master/apps/next/pages/leaflet.js) 61 | 62 | ``` jsx 63 | // pages/map.js 64 | import dynamic from 'next/dynamic' 65 | import NextHead from 'next/head' 66 | const HelloWorldMap = dynamic(import('../components/HelloWorldMap'), {ssr: false}) 67 | 68 | export default () => { 69 | return ( 70 |
71 | 72 | 75 | 76 | 77 |
78 | ) 79 | } 80 | ``` -------------------------------------------------------------------------------- /docs/monaco-editor-with-next.md: -------------------------------------------------------------------------------- 1 | # Monaco Editor with Next.js 2 | 3 | [![live demo](https://img.shields.io/badge/live-demo-green.svg?style=plastic)](https://resourcessnippets-next.now.sh/monaco) 4 | 5 | This uses [@timkendrick/monaco-editor](https://github.com/timkendrick/monaco-editor) 6 | which has support for the combination of WebPack and a node-like browser environment 7 | (that has global variables like `process` and `module` defined). 8 | 9 | ## Create the project and add the dependencies 10 | 11 | Create a next app: 12 | 13 | ``` bash 14 | create-next-app myapp 15 | ``` 16 | 17 | Install the dependencies: 18 | 19 | ``` bash 20 | npm install react-monaco-editor @timkendrick/monaco-editor express @zeit/next-css css-loader --save` 21 | ``` 22 | 23 | ## Add the component 24 | 25 | [components/code-with-monaco.js](https://github.com/resources/snippets/blob/master/apps/next/components/code-with-monaco.js) 26 | 27 | ``` jsx 28 | window.MonacoEnvironment = { baseUrl: '/monaco-editor-external' }; 29 | import * as monaco from '@timkendrick/monaco-editor/dist/external' 30 | import React, { Component } from 'react' 31 | import MonacoEditor from 'react-monaco-editor' 32 | import '../node_modules/@timkendrick/monaco-editor/dist/external/monaco.css' 33 | 34 | export default (props) => ( 35 | null} 43 | editorDidMount={() => null} 44 | {...props} 45 | /> 46 | ) 47 | ``` 48 | 49 | ## Set up the CSS loader for webpack 50 | 51 | [next.config.js](https://github.com/resources/snippets/blob/master/apps/next/next.config.js) 52 | 53 | ``` js 54 | const withCSS = require('@zeit/next-css') 55 | module.exports = withCSS({ 56 | webpack: (config) => { 57 | // Fixes npm packages that depend on `fs` module 58 | config.node = { 59 | fs: 'empty' 60 | } 61 | 62 | return config 63 | } 64 | }) 65 | ``` 66 | 67 | ## Set up a custom server with a static middleware for Monaco Editor 68 | 69 | [server.js](https://github.com/resources/snippets/blob/master/apps/next/server.js) 70 | 71 | ``` js 72 | const express = require('express') 73 | const next = require('next') 74 | 75 | const port = parseInt(process.env.PORT, 10) || 3000 76 | const dev = process.env.NODE_ENV !== 'production' 77 | const app = next({ dev }) 78 | const handle = app.getRequestHandler() 79 | 80 | app.prepare() 81 | .then(() => { 82 | const server = express() 83 | 84 | server.use( 85 | '/monaco-editor-external', 86 | express.static(`${__dirname}/node_modules/@timkendrick/monaco-editor/dist/external`) 87 | ) 88 | 89 | server.get('*', (req, res) => { 90 | return handle(req, res) 91 | }) 92 | 93 | server.listen(port, err => { 94 | if (err) throw err 95 | console.log(`> Ready on http://localhost:${port}`) 96 | }) 97 | }) 98 | ``` 99 | 100 | Change the `scripts` in `package.json` to use the custom server: 101 | 102 | [package.json](https://github.com/resources/snippets/blob/master/apps/next/package.json) 103 | 104 | ``` json 105 | { 106 | "dev": "node server.js", 107 | "build": "next build", 108 | "start": "NODE_ENV=production node server.js" 109 | } 110 | ``` 111 | 112 | ## Use the component in a page 113 | 114 | To use this component, use a dynamic import with `ssr` set to `false`. 115 | These example pages show that Next.js can switch pages relatively cleanly 116 | with these editor components on them, thanks to `react-monaco-editor` and 117 | the [alternative build of monaco-editor](https://github.com/timkendrick/monaco-editor). 118 | 119 | [pages/monaco.js](https://github.com/resources/snippets/blob/master/monaco-editor-with-next/pages/monaco.js) 120 | 121 | ``` jsx 122 | import dynamic from 'next/dynamic' 123 | const CodeWithMonaco = dynamic(import('../components/code-with-monaco'), {ssr: false}) 124 | import Link from 'next/link' 125 | 126 | export default () => { 127 | const someJs = [ 128 | "import {myCoolFunc} from './utils'", 129 | 'export default async () => {', 130 | ' await myCoolFunc()', 131 | '}' 132 | ].join("\n") 133 | return ( 134 |
135 |
136 | Other Page 137 |
138 | 139 |
140 | ) 141 | } 142 | ``` 143 | 144 | [pages/other-page.js](https://github.com/resources/snippets/blob/master/monaco-editor-with-next/pages/monaco-other-page.js) 145 | 146 | ``` jsx 147 | import dynamic from 'next/dynamic' 148 | const CodeWithMonaco = dynamic(import('../components/code-with-monaco'), {ssr: false}) 149 | import Link from 'next/link' 150 | 151 | export default () => { 152 | const someCss = [ 153 | '.exampleDiv {', 154 | ' background-color: #003;', 155 | ' color: #ccc;', 156 | '}' 157 | ].join("\n") 158 | const someJs = [ 159 | "import {myCoolFunc} from './utils'", 160 | 'export default async () => {', 161 | ' await myCoolFunc()', 162 | '}' 163 | ].join("\n") 164 | return ( 165 |
166 |
167 | Home 168 |
169 | 170 | 171 |
172 | ) 173 | } 174 | ``` 175 | 176 | ## Run it 177 | 178 | Run it with `next dev` and go to `localhost:3000`. 179 | -------------------------------------------------------------------------------- /github-oauth-with-hapi-v16/README.md: -------------------------------------------------------------------------------- 1 | # [GitHub OAuth with Hapi v16][url] 2 | 3 | - `npm init -y` 4 | - `npm install hapi@16 hapi-auth-cookie@7 bell@8 --save` 5 | - generate a session key: 6 | `export SESSION_KEY=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")` 7 | - go to github.com > Settings > Developer Settings > OAuth Apps and add a new app 8 | - you can use your personal web page for the application URL and a temporary callback URL 9 | - you can change the callback URL later 10 | - set the client ID: `export GITHUB_CLIENT_ID=YOUR_CLIENT_ID` 11 | - set the client secret: `export GITHUB_CLIENT_SECRET=YOUR_CLIENT_SECRET` 12 | - test with ngrok: 13 | - run `npm start` 14 | - in a new console tab, run `brew cask install ngrok` 15 | - run `ngrok http 3000` 16 | - set the callback URL to https://yourngrokurl.ngrok.io/login on the GitHub OAuth app page 17 | - open https://yourngrokurl.ngrok.io/ in your browser 18 | - deploy with now: 19 | - set up https://zeit.co/now if you haven't already 20 | - run `now`: 21 | now -e SESSION_KEY=$SESSION_KEY \ 22 | -e GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID \ 23 | -e GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET 24 | - run `now alias set https://auto-generated-subdomain.now.sh your-now-subdomain` 25 | - update the callback URL to https://your-now-subdomain.now.sh/login on the GitHub OAuth app page 26 | - open https://your-now-subdomain.now.sh/ in your browser 27 | - live demo is at https://github-oauth-with-hapi-example.now.sh/ 28 | 29 | [url]: https://github.com/resources/snippets/tree/master/github-oauth-with-hapi-v16 30 | ``` js 31 | 'use strict'; 32 | 33 | const Hapi = require('hapi'); 34 | const HapiAuthCookie = require('hapi-auth-cookie'); 35 | const Bell = require('bell'); 36 | 37 | const server = new Hapi.Server(); 38 | 39 | server.connection({port: process.env.PORT || 3000}); 40 | 41 | async function start() { 42 | await server.register(HapiAuthCookie); 43 | await server.register(Bell); 44 | 45 | server.auth.strategy('session', 'cookie', { 46 | password: process.env.SESSION_KEY, 47 | redirectTo: '/', 48 | }); 49 | 50 | server.auth.strategy('github', 'bell', { 51 | provider: 'github', 52 | scope: ['user:email'], 53 | password: process.env.SESSION_KEY, 54 | clientId: process.env.GITHUB_CLIENT_ID, 55 | clientSecret: process.env.GITHUB_CLIENT_SECRET, 56 | forceHttps: true, // needed to use ngrok when testing locally 57 | }); 58 | 59 | server.route({ 60 | method: 'GET', 61 | path: '/', 62 | config: { 63 | auth: {strategy: 'session', mode: 'try'}, 64 | plugins: {'hapi-auth-cookie': {redirectTo: false}}, 65 | handler: (request, reply) => { 66 | if (request.auth.credentials) { 67 | const {username, email} = request.auth.credentials; 68 | reply(`
${JSON.stringify({username, email}, null, 2)}
69 |

Go to /secret to see a protected page!

`); 70 | } else { 71 | reply('Go to /login to sign in!'); 72 | } 73 | } 74 | } 75 | }); 76 | 77 | server.route({ 78 | method: ['GET', 'POST'], 79 | path: '/login', 80 | config: { 81 | auth: 'github', 82 | handler: (request, reply) => { 83 | if (! request.auth.isAuthenticated) { 84 | return reply(`Auth failed: ${request.auth.error.message}`); 85 | } 86 | 87 | const {username, email} = request.auth.credentials.profile; 88 | request.cookieAuth.set({username, email}); 89 | 90 | return reply.redirect('/'); 91 | } 92 | } 93 | }); 94 | 95 | server.route({ 96 | method: 'GET', 97 | path: '/secret', 98 | config: { 99 | auth: 'session', 100 | handler: (request, reply) => { 101 | reply('You should only see this when logged in.'); 102 | } 103 | } 104 | }); 105 | 106 | server.route({ 107 | method: 'GET', 108 | path: '/logout', 109 | handler: (request, reply) => { 110 | request.cookieAuth.clear(); 111 | reply.redirect('/'); 112 | } 113 | }); 114 | 115 | await server.start(); 116 | } 117 | 118 | start().then(() => { 119 | console.log(`Server running at: ${server.info.uri}`); 120 | }).catch(err => { 121 | console.error(err); 122 | process.exit(1); 123 | }); 124 | ``` -------------------------------------------------------------------------------- /github-oauth-with-hapi-v16/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oauth-hapi", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accept": { 8 | "version": "2.1.4", 9 | "resolved": "https://registry.npmjs.org/accept/-/accept-2.1.4.tgz", 10 | "integrity": "sha1-iHr1TO7lx/RDBGGXHsQAxh0JrLs=", 11 | "requires": { 12 | "boom": "5.2.0", 13 | "hoek": "4.2.0" 14 | }, 15 | "dependencies": { 16 | "boom": { 17 | "version": "5.2.0", 18 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 19 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 20 | "requires": { 21 | "hoek": "4.2.0" 22 | } 23 | } 24 | } 25 | }, 26 | "ammo": { 27 | "version": "2.0.4", 28 | "resolved": "https://registry.npmjs.org/ammo/-/ammo-2.0.4.tgz", 29 | "integrity": "sha1-v4CqshFpjqePY+9efxE91dnokX8=", 30 | "requires": { 31 | "boom": "5.2.0", 32 | "hoek": "4.2.0" 33 | }, 34 | "dependencies": { 35 | "boom": { 36 | "version": "5.2.0", 37 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 38 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 39 | "requires": { 40 | "hoek": "4.2.0" 41 | } 42 | } 43 | } 44 | }, 45 | "b64": { 46 | "version": "3.0.3", 47 | "resolved": "https://registry.npmjs.org/b64/-/b64-3.0.3.tgz", 48 | "integrity": "sha512-Pbeh0i6OLubPJdIdCepn8ZQHwN2MWznZHbHABSTEfQ706ie+yuxNSaPdqX1xRatT6WanaS1EazMiSg0NUW2XxQ==" 49 | }, 50 | "bell": { 51 | "version": "8.9.0", 52 | "resolved": "https://registry.npmjs.org/bell/-/bell-8.9.0.tgz", 53 | "integrity": "sha512-tibCCgKaP9ahjGAJs/YDpAWWZyLmlvJfjMa7ElPA9/mkmCvswedvouI0DVRaa/1zfKqQ9GTy6Y2ZMhCfJbCPfQ==", 54 | "requires": { 55 | "boom": "4.2.0", 56 | "cryptiles": "3.1.2", 57 | "hoek": "4.2.0", 58 | "joi": "10.6.0", 59 | "wreck": "10.0.0" 60 | } 61 | }, 62 | "boom": { 63 | "version": "4.2.0", 64 | "resolved": "https://registry.npmjs.org/boom/-/boom-4.2.0.tgz", 65 | "integrity": "sha1-wadBdLEfu6Ij9hYtT9iFGhuCpTY=", 66 | "requires": { 67 | "hoek": "4.2.0" 68 | } 69 | }, 70 | "call": { 71 | "version": "4.0.2", 72 | "resolved": "https://registry.npmjs.org/call/-/call-4.0.2.tgz", 73 | "integrity": "sha1-33b19R7o3Ui4VqyEAPfmnm1zmcQ=", 74 | "requires": { 75 | "boom": "5.2.0", 76 | "hoek": "4.2.0" 77 | }, 78 | "dependencies": { 79 | "boom": { 80 | "version": "5.2.0", 81 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 82 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 83 | "requires": { 84 | "hoek": "4.2.0" 85 | } 86 | } 87 | } 88 | }, 89 | "catbox": { 90 | "version": "7.1.5", 91 | "resolved": "https://registry.npmjs.org/catbox/-/catbox-7.1.5.tgz", 92 | "integrity": "sha512-4fui5lELzqZ+9cnaAP/BcqXTH6LvWLBRtFhJ0I4FfgfXiSaZcf6k9m9dqOyChiTxNYtvLk7ZMYSf7ahMq3bf5A==", 93 | "requires": { 94 | "boom": "5.2.0", 95 | "hoek": "4.2.0", 96 | "joi": "10.6.0" 97 | }, 98 | "dependencies": { 99 | "boom": { 100 | "version": "5.2.0", 101 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 102 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 103 | "requires": { 104 | "hoek": "4.2.0" 105 | } 106 | } 107 | } 108 | }, 109 | "catbox-memory": { 110 | "version": "2.0.4", 111 | "resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-2.0.4.tgz", 112 | "integrity": "sha1-Qz4lWQLK9UIz0ShkKcj03xToItU=", 113 | "requires": { 114 | "hoek": "4.2.0" 115 | } 116 | }, 117 | "content": { 118 | "version": "3.0.6", 119 | "resolved": "https://registry.npmjs.org/content/-/content-3.0.6.tgz", 120 | "integrity": "sha512-tyl3fRp8jOHsQR0X9vrIy0mKQccv0tA9/RlvLl514eA7vHOJr/TnmMTpgQjInwbeW9IOQVy0OECGAuQNUa0nnQ==", 121 | "requires": { 122 | "boom": "5.2.0" 123 | }, 124 | "dependencies": { 125 | "boom": { 126 | "version": "5.2.0", 127 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 128 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 129 | "requires": { 130 | "hoek": "4.2.0" 131 | } 132 | } 133 | } 134 | }, 135 | "cryptiles": { 136 | "version": "3.1.2", 137 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", 138 | "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", 139 | "requires": { 140 | "boom": "5.2.0" 141 | }, 142 | "dependencies": { 143 | "boom": { 144 | "version": "5.2.0", 145 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 146 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 147 | "requires": { 148 | "hoek": "4.2.0" 149 | } 150 | } 151 | } 152 | }, 153 | "hapi": { 154 | "version": "16.6.2", 155 | "resolved": "https://registry.npmjs.org/hapi/-/hapi-16.6.2.tgz", 156 | "integrity": "sha512-DBeIsge8nn3rBSFGX/btOwwkkVIMTuWHIkkiWtRAq8IHxhBfmVSewPm4BprU50PQjncQFw44JTN77l/pMKVHlA==", 157 | "requires": { 158 | "accept": "2.1.4", 159 | "ammo": "2.0.4", 160 | "boom": "5.2.0", 161 | "call": "4.0.2", 162 | "catbox": "7.1.5", 163 | "catbox-memory": "2.0.4", 164 | "cryptiles": "3.1.2", 165 | "heavy": "4.0.4", 166 | "hoek": "4.2.0", 167 | "iron": "4.0.5", 168 | "items": "2.1.1", 169 | "joi": "11.4.0", 170 | "mimos": "3.0.3", 171 | "podium": "1.3.0", 172 | "shot": "3.4.2", 173 | "statehood": "5.0.3", 174 | "subtext": "5.0.0", 175 | "topo": "2.0.2" 176 | }, 177 | "dependencies": { 178 | "boom": { 179 | "version": "5.2.0", 180 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 181 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 182 | "requires": { 183 | "hoek": "4.2.0" 184 | } 185 | }, 186 | "isemail": { 187 | "version": "3.0.0", 188 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.0.0.tgz", 189 | "integrity": "sha512-rz0ng/c+fX+zACpLgDB8fnUQ845WSU06f4hlhk4K8TJxmR6f5hyvitu9a9JdMD7aq/P4E0XdG1uaab2OiXgHlA==", 190 | "requires": { 191 | "punycode": "2.1.0" 192 | } 193 | }, 194 | "joi": { 195 | "version": "11.4.0", 196 | "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", 197 | "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", 198 | "requires": { 199 | "hoek": "4.2.0", 200 | "isemail": "3.0.0", 201 | "topo": "2.0.2" 202 | } 203 | } 204 | } 205 | }, 206 | "hapi-auth-cookie": { 207 | "version": "7.0.0", 208 | "resolved": "https://registry.npmjs.org/hapi-auth-cookie/-/hapi-auth-cookie-7.0.0.tgz", 209 | "integrity": "sha1-G7kTDYWrDv4C999RjoZIZ2FqSaQ=", 210 | "requires": { 211 | "boom": "3.2.2", 212 | "hoek": "4.2.0", 213 | "joi": "8.4.2" 214 | }, 215 | "dependencies": { 216 | "boom": { 217 | "version": "3.2.2", 218 | "resolved": "https://registry.npmjs.org/boom/-/boom-3.2.2.tgz", 219 | "integrity": "sha1-DwzF0ErcUAO4x9cfQsynJx/vDng=", 220 | "requires": { 221 | "hoek": "4.2.0" 222 | } 223 | }, 224 | "joi": { 225 | "version": "8.4.2", 226 | "resolved": "https://registry.npmjs.org/joi/-/joi-8.4.2.tgz", 227 | "integrity": "sha1-vXd0ZY/pkFjYmU7R1LmWJITruFk=", 228 | "requires": { 229 | "hoek": "4.2.0", 230 | "isemail": "2.2.1", 231 | "moment": "2.20.1", 232 | "topo": "2.0.2" 233 | } 234 | } 235 | } 236 | }, 237 | "heavy": { 238 | "version": "4.0.4", 239 | "resolved": "https://registry.npmjs.org/heavy/-/heavy-4.0.4.tgz", 240 | "integrity": "sha1-NskTNsAMz+hSyqTRUwhjNc0vAOk=", 241 | "requires": { 242 | "boom": "5.2.0", 243 | "hoek": "4.2.0", 244 | "joi": "10.6.0" 245 | }, 246 | "dependencies": { 247 | "boom": { 248 | "version": "5.2.0", 249 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 250 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 251 | "requires": { 252 | "hoek": "4.2.0" 253 | } 254 | } 255 | } 256 | }, 257 | "hoek": { 258 | "version": "4.2.0", 259 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", 260 | "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" 261 | }, 262 | "iron": { 263 | "version": "4.0.5", 264 | "resolved": "https://registry.npmjs.org/iron/-/iron-4.0.5.tgz", 265 | "integrity": "sha1-TwQszri5c480a1mqc0yDqJvDFCg=", 266 | "requires": { 267 | "boom": "5.2.0", 268 | "cryptiles": "3.1.2", 269 | "hoek": "4.2.0" 270 | }, 271 | "dependencies": { 272 | "boom": { 273 | "version": "5.2.0", 274 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 275 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 276 | "requires": { 277 | "hoek": "4.2.0" 278 | } 279 | } 280 | } 281 | }, 282 | "isemail": { 283 | "version": "2.2.1", 284 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz", 285 | "integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY=" 286 | }, 287 | "items": { 288 | "version": "2.1.1", 289 | "resolved": "https://registry.npmjs.org/items/-/items-2.1.1.tgz", 290 | "integrity": "sha1-i9FtnIOxlSneWuoyGsqtp4NkoZg=" 291 | }, 292 | "joi": { 293 | "version": "10.6.0", 294 | "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", 295 | "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", 296 | "requires": { 297 | "hoek": "4.2.0", 298 | "isemail": "2.2.1", 299 | "items": "2.1.1", 300 | "topo": "2.0.2" 301 | } 302 | }, 303 | "mime-db": { 304 | "version": "1.32.0", 305 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.32.0.tgz", 306 | "integrity": "sha512-+ZWo/xZN40Tt6S+HyakUxnSOgff+JEdaneLWIm0Z6LmpCn5DMcZntLyUY5c/rTDog28LhXLKOUZKoTxTCAdBVw==" 307 | }, 308 | "mimos": { 309 | "version": "3.0.3", 310 | "resolved": "https://registry.npmjs.org/mimos/-/mimos-3.0.3.tgz", 311 | "integrity": "sha1-uRCQcq03jCty9qAQHEPd+ys2ZB8=", 312 | "requires": { 313 | "hoek": "4.2.0", 314 | "mime-db": "1.32.0" 315 | } 316 | }, 317 | "moment": { 318 | "version": "2.20.1", 319 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", 320 | "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==" 321 | }, 322 | "nigel": { 323 | "version": "2.0.2", 324 | "resolved": "https://registry.npmjs.org/nigel/-/nigel-2.0.2.tgz", 325 | "integrity": "sha1-k6GGb7DFLYc5CqdeKxYfS1x15bE=", 326 | "requires": { 327 | "hoek": "4.2.0", 328 | "vise": "2.0.2" 329 | } 330 | }, 331 | "pez": { 332 | "version": "2.1.5", 333 | "resolved": "https://registry.npmjs.org/pez/-/pez-2.1.5.tgz", 334 | "integrity": "sha1-XsLMYlAMw+tCNtSkFM9aF7XrUAc=", 335 | "requires": { 336 | "b64": "3.0.3", 337 | "boom": "5.2.0", 338 | "content": "3.0.6", 339 | "hoek": "4.2.0", 340 | "nigel": "2.0.2" 341 | }, 342 | "dependencies": { 343 | "boom": { 344 | "version": "5.2.0", 345 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 346 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 347 | "requires": { 348 | "hoek": "4.2.0" 349 | } 350 | } 351 | } 352 | }, 353 | "podium": { 354 | "version": "1.3.0", 355 | "resolved": "https://registry.npmjs.org/podium/-/podium-1.3.0.tgz", 356 | "integrity": "sha512-ZIujqk1pv8bRZNVxwwwq0BhXilZ2udycQT3Kp8ah3f3TcTmVg7ILJsv/oLf47gRa2qeiP584lNq+pfvS9U3aow==", 357 | "requires": { 358 | "hoek": "4.2.0", 359 | "items": "2.1.1", 360 | "joi": "10.6.0" 361 | } 362 | }, 363 | "punycode": { 364 | "version": "2.1.0", 365 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", 366 | "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" 367 | }, 368 | "shot": { 369 | "version": "3.4.2", 370 | "resolved": "https://registry.npmjs.org/shot/-/shot-3.4.2.tgz", 371 | "integrity": "sha1-Hlw/bysmZJrcQvfrNQIUpaApHWc=", 372 | "requires": { 373 | "hoek": "4.2.0", 374 | "joi": "10.6.0" 375 | } 376 | }, 377 | "statehood": { 378 | "version": "5.0.3", 379 | "resolved": "https://registry.npmjs.org/statehood/-/statehood-5.0.3.tgz", 380 | "integrity": "sha512-YrPrCt10t3ImH/JMO5szSwX7sCm8HoqVl3VFLOa9EZ1g/qJx/ZmMhN+2uzPPB/vaU6hpkJpXxcBWsgIkkG+MXA==", 381 | "requires": { 382 | "boom": "5.2.0", 383 | "cryptiles": "3.1.2", 384 | "hoek": "4.2.0", 385 | "iron": "4.0.5", 386 | "items": "2.1.1", 387 | "joi": "10.6.0" 388 | }, 389 | "dependencies": { 390 | "boom": { 391 | "version": "5.2.0", 392 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 393 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 394 | "requires": { 395 | "hoek": "4.2.0" 396 | } 397 | } 398 | } 399 | }, 400 | "subtext": { 401 | "version": "5.0.0", 402 | "resolved": "https://registry.npmjs.org/subtext/-/subtext-5.0.0.tgz", 403 | "integrity": "sha512-2nXG1G1V+K64Z20cQII7k0s38J2DSycMXBLMAk9RXUFG0uAkAbLSVoa88croX9VhTdBCJbLAe9g6LmzKwpJhhQ==", 404 | "requires": { 405 | "boom": "5.2.0", 406 | "content": "3.0.6", 407 | "hoek": "4.2.0", 408 | "pez": "2.1.5", 409 | "wreck": "12.5.1" 410 | }, 411 | "dependencies": { 412 | "boom": { 413 | "version": "5.2.0", 414 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 415 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 416 | "requires": { 417 | "hoek": "4.2.0" 418 | } 419 | }, 420 | "wreck": { 421 | "version": "12.5.1", 422 | "resolved": "https://registry.npmjs.org/wreck/-/wreck-12.5.1.tgz", 423 | "integrity": "sha512-l5DUGrc+yDyIflpty1x9XuMj1ehVjC/dTbF3/BasOO77xk0EdEa4M/DuOY8W88MQDAD0fEDqyjc8bkIMHd2E9A==", 424 | "requires": { 425 | "boom": "5.2.0", 426 | "hoek": "4.2.0" 427 | } 428 | } 429 | } 430 | }, 431 | "topo": { 432 | "version": "2.0.2", 433 | "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", 434 | "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", 435 | "requires": { 436 | "hoek": "4.2.0" 437 | } 438 | }, 439 | "vise": { 440 | "version": "2.0.2", 441 | "resolved": "https://registry.npmjs.org/vise/-/vise-2.0.2.tgz", 442 | "integrity": "sha1-awjo+0y3bjpQzW3Q7DczjoEaDTk=", 443 | "requires": { 444 | "hoek": "4.2.0" 445 | } 446 | }, 447 | "wreck": { 448 | "version": "10.0.0", 449 | "resolved": "https://registry.npmjs.org/wreck/-/wreck-10.0.0.tgz", 450 | "integrity": "sha1-mKuIL4XhalJjMlB/EB9aeEEWIng=", 451 | "requires": { 452 | "boom": "4.2.0", 453 | "hoek": "4.2.0" 454 | } 455 | } 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /github-oauth-with-hapi-v16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oauth-hapi", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bell": "^8.9.0", 15 | "hapi": "^16.6.2", 16 | "hapi-auth-cookie": "^7.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /github-oauth-with-hapi-v16/server.js: -------------------------------------------------------------------------------- 1 | // # [GitHub OAuth with Hapi v16][url] 2 | // 3 | // - `npm init -y` 4 | // - `npm install hapi@16 hapi-auth-cookie@7 bell@8 --save` 5 | // - generate a session key: 6 | // `export SESSION_KEY=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")` 7 | // - go to github.com > Settings > Developer Settings > OAuth Apps and add a new app 8 | // - you can use your personal web page for the application URL and a temporary callback URL 9 | // - you can change the callback URL later 10 | // - set the client ID: `export GITHUB_CLIENT_ID=YOUR_CLIENT_ID` 11 | // - set the client secret: `export GITHUB_CLIENT_SECRET=YOUR_CLIENT_SECRET` 12 | // - test with ngrok: 13 | // - run `npm start` 14 | // - in a new console tab, run `brew cask install ngrok` 15 | // - run `ngrok http 3000` 16 | // - set the callback URL to https://yourngrokurl.ngrok.io/login on the GitHub OAuth app page 17 | // - open https://yourngrokurl.ngrok.io/ in your browser 18 | // - deploy with now: 19 | // - set up https://zeit.co/now if you haven't already 20 | // - run `now`: 21 | // now -e SESSION_KEY=$SESSION_KEY \ 22 | // -e GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID \ 23 | // -e GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET 24 | // - run `now alias set https://auto-generated-subdomain.now.sh your-now-subdomain` 25 | // - update the callback URL to https://your-now-subdomain.now.sh/login on the GitHub OAuth app page 26 | // - open https://your-now-subdomain.now.sh/ in your browser 27 | // - live demo is at https://github-oauth-with-hapi-example.now.sh/ 28 | // 29 | // [url]: https://github.com/resources/snippets/tree/master/github-oauth-with-hapi-v16 30 | 'use strict'; 31 | 32 | const Hapi = require('hapi'); 33 | const HapiAuthCookie = require('hapi-auth-cookie'); 34 | const Bell = require('bell'); 35 | 36 | const server = new Hapi.Server(); 37 | 38 | server.connection({port: process.env.PORT || 3000}); 39 | 40 | async function start() { 41 | await server.register(HapiAuthCookie); 42 | await server.register(Bell); 43 | 44 | server.auth.strategy('session', 'cookie', { 45 | password: process.env.SESSION_KEY, 46 | redirectTo: '/', 47 | }); 48 | 49 | server.auth.strategy('github', 'bell', { 50 | provider: 'github', 51 | scope: ['user:email'], 52 | password: process.env.SESSION_KEY, 53 | clientId: process.env.GITHUB_CLIENT_ID, 54 | clientSecret: process.env.GITHUB_CLIENT_SECRET, 55 | forceHttps: true, // needed to use ngrok when testing locally 56 | }); 57 | 58 | server.route({ 59 | method: 'GET', 60 | path: '/', 61 | config: { 62 | auth: {strategy: 'session', mode: 'try'}, 63 | plugins: {'hapi-auth-cookie': {redirectTo: false}}, 64 | handler: (request, reply) => { 65 | if (request.auth.credentials) { 66 | const {username, email} = request.auth.credentials; 67 | reply(`
${JSON.stringify({username, email}, null, 2)}
68 |

Go to /secret to see a protected page!

`); 69 | } else { 70 | reply('Go to /login to sign in!'); 71 | } 72 | } 73 | } 74 | }); 75 | 76 | server.route({ 77 | method: ['GET', 'POST'], 78 | path: '/login', 79 | config: { 80 | auth: 'github', 81 | handler: (request, reply) => { 82 | if (! request.auth.isAuthenticated) { 83 | return reply(`Auth failed: ${request.auth.error.message}`); 84 | } 85 | 86 | const {username, email} = request.auth.credentials.profile; 87 | request.cookieAuth.set({username, email}); 88 | 89 | return reply.redirect('/'); 90 | } 91 | } 92 | }); 93 | 94 | server.route({ 95 | method: 'GET', 96 | path: '/secret', 97 | config: { 98 | auth: 'session', 99 | handler: (request, reply) => { 100 | reply('You should only see this when logged in.'); 101 | } 102 | } 103 | }); 104 | 105 | server.route({ 106 | method: 'GET', 107 | path: '/logout', 108 | handler: (request, reply) => { 109 | request.cookieAuth.clear(); 110 | reply.redirect('/'); 111 | } 112 | }); 113 | 114 | await server.start(); 115 | } 116 | 117 | start().then(() => { 118 | console.log(`Server running at: ${server.info.uri}`); 119 | }).catch(err => { 120 | console.error(err); 121 | process.exit(1); 122 | }); -------------------------------------------------------------------------------- /github-oauth-with-hapi-v17/README.md: -------------------------------------------------------------------------------- 1 | # [GitHub OAuth with Hapi v17](https://github.com/resources/snippets/tree/master/github-oauth-with-hapi-v16) 2 | 3 | - `npm init -y` 4 | - `npm install hapi hapi-auth-cookie github:makeomatic/bell#hapi17 --save` 5 | - generate a session key: 6 | `export SESSION_KEY=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")` 7 | - go to github.com > Settings > Developer Settings > OAuth Apps and add a new app 8 | - you can use your personal web page for the application URL and a temporary callback URL 9 | - you can change the callback URL later 10 | - set the client ID: `export GITHUB_CLIENT_ID=YOUR_CLIENT_ID` 11 | - set the client secret: `export GITHUB_CLIENT_SECRET=YOUR_CLIENT_SECRET` 12 | - test with ngrok: 13 | - run `npm start` 14 | - in a new console tab, run `brew cask install ngrok` 15 | - run `ngrok http 3000` 16 | - set the callback URL to https://yourngrokurl.ngrok.io/auth/github on the GitHub OAuth app page 17 | - open https://yourngrokurl.ngrok.io/ in your browser 18 | - deploy with now: 19 | - set up https://zeit.co/now if you haven't already 20 | - run `now`: 21 | now -e SESSION_KEY=$SESSION_KEY \ 22 | -e GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID \ 23 | -e GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET 24 | - run `now alias set https://auto-generated-subdomain.now.sh your-now-subdomain` 25 | - update the callback URL to https://your-now-subdomain.now.sh/auth/github on the GitHub OAuth app page 26 | - open https://your-now-subdomain.now.sh/ in your browser 27 | 28 | ``` js 29 | 'use strict'; 30 | 31 | const Hapi = require('hapi'); 32 | const HapiAuthCookie = require('hapi-auth-cookie'); 33 | const Bell = require('bell'); 34 | 35 | async function start() { 36 | const server = Hapi.server({ 37 | port: process.env.PORT || 3000 38 | }); 39 | 40 | await server.register(HapiAuthCookie); 41 | await server.register(Bell); 42 | 43 | server.auth.strategy('session', 'cookie', { 44 | password: process.env.SESSION_KEY, 45 | redirectTo: '/', 46 | }); 47 | 48 | server.auth.strategy('github', 'bell', { 49 | provider: 'github', 50 | scope: ['user:email'], 51 | password: process.env.SESSION_KEY, 52 | clientId: process.env.GITHUB_CLIENT_ID, 53 | clientSecret: process.env.GITHUB_CLIENT_SECRET, 54 | forceHttps: true, // needed to use ngrok when testing locally 55 | }); 56 | 57 | server.route({ 58 | method: 'GET', 59 | path: '/', 60 | config: { 61 | auth: {strategy: 'session', mode: 'try'}, 62 | plugins: {'hapi-auth-cookie': {redirectTo: false}}, 63 | handler: (request, h) => { 64 | if (request.auth.credentials) { 65 | const {username, email} = request.auth.credentials; 66 | return `
${JSON.stringify({username, email}, null, 2)}
67 |

Go to /secret to see a protected page!

`; 68 | } else { 69 | return 'Go to /auth/github to sign in!'; 70 | } 71 | } 72 | } 73 | }); 74 | 75 | server.route({ 76 | method: ['GET', 'POST'], 77 | path: '/auth/github', 78 | config: { 79 | auth: 'github', 80 | handler: async (request, h) => { 81 | if (! request.auth.isAuthenticated) { 82 | return `Auth failed: ${request.auth.error.message}`; 83 | } 84 | 85 | const {username, email} = request.auth.credentials.profile; 86 | request.cookieAuth.set({username, email}); 87 | 88 | return h.redirect('/'); 89 | } 90 | } 91 | }); 92 | 93 | server.route({ 94 | method: 'GET', 95 | path: '/secret', 96 | config: { 97 | auth: 'session', 98 | handler: (request, h) => { 99 | return 'You should only see this when logged in.'; 100 | } 101 | } 102 | }); 103 | 104 | server.route({ 105 | method: 'GET', 106 | path: '/logout', 107 | handler: (request, h) => { 108 | request.cookieAuth.clear(); 109 | return h.redirect('/'); 110 | } 111 | }); 112 | 113 | await server.start(); 114 | console.log(`Server running at: ${server.info.uri}`); 115 | } 116 | 117 | start().catch(err => { 118 | console.error(err); 119 | process.exit(1); 120 | }); 121 | ``` -------------------------------------------------------------------------------- /github-oauth-with-hapi-v17/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-oauth-with-hapi-v17", 3 | "version": "0.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "bell": { 8 | "version": "github:makeomatic/bell#f7bf7c9e0863d307708d2bcd79f0afa65f8e72ba", 9 | "requires": { 10 | "boom": "7.1.1", 11 | "cryptiles": "4.1.1", 12 | "hoek": "5.0.2", 13 | "joi": "13.0.2", 14 | "wreck": "14.0.2" 15 | }, 16 | "dependencies": { 17 | "boom": { 18 | "version": "7.1.1", 19 | "resolved": "https://registry.npmjs.org/boom/-/boom-7.1.1.tgz", 20 | "integrity": "sha512-qwEARHTliqgEQiVkzKkkbLt3q0vRPIW60VRZ8zRnbjsm7INkPe9NxfAYDDYLZOdhxyUHa1gIe639Cx7t6RH/4A==", 21 | "requires": { 22 | "hoek": "5.0.2" 23 | } 24 | }, 25 | "cryptiles": { 26 | "version": "4.1.1", 27 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.1.tgz", 28 | "integrity": "sha512-YuQUPbcOmaZsdvxJZ25DCA1W+lLIRoPJKBDKin+St1RCYEERSfoe1d25B1MvWNHN3e8SpFSVsqYvEUjp8J9H2w==", 29 | "requires": { 30 | "boom": "7.1.1" 31 | } 32 | }, 33 | "hoek": { 34 | "version": "5.0.2", 35 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.2.tgz", 36 | "integrity": "sha512-NA10UYP9ufCtY2qYGkZktcQXwVyYK4zK0gkaFSB96xhtlo6V8tKXdQgx8eHolQTRemaW0uLn8BhjhwqrOU+QLQ==" 37 | }, 38 | "isemail": { 39 | "version": "3.0.0", 40 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.0.0.tgz", 41 | "integrity": "sha512-rz0ng/c+fX+zACpLgDB8fnUQ845WSU06f4hlhk4K8TJxmR6f5hyvitu9a9JdMD7aq/P4E0XdG1uaab2OiXgHlA==", 42 | "requires": { 43 | "punycode": "2.1.0" 44 | } 45 | }, 46 | "joi": { 47 | "version": "13.0.2", 48 | "resolved": "https://registry.npmjs.org/joi/-/joi-13.0.2.tgz", 49 | "integrity": "sha512-kVka3LaHQyENvcMW4WJPSepGM43oCofcKxfs9HbbKd/FrwBAAt4lNNTPKOzSMmV53GIspmNO4U3O2TzoGvxxCA==", 50 | "requires": { 51 | "hoek": "5.0.2", 52 | "isemail": "3.0.0", 53 | "topo": "3.0.0" 54 | } 55 | }, 56 | "topo": { 57 | "version": "3.0.0", 58 | "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz", 59 | "integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==", 60 | "requires": { 61 | "hoek": "5.0.2" 62 | } 63 | }, 64 | "wreck": { 65 | "version": "14.0.2", 66 | "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.0.2.tgz", 67 | "integrity": "sha512-QCm3omWNJUseqrSzwX2QZi1rBbmCfbFHJAXputLLyZ37VSiFnSYQB0ms/mPnSvrlIu7GVm89Y/gBNhSY26uVIQ==", 68 | "requires": { 69 | "boom": "7.1.1", 70 | "hoek": "5.0.2" 71 | } 72 | } 73 | } 74 | }, 75 | "big-time": { 76 | "version": "2.0.0", 77 | "resolved": "https://registry.npmjs.org/big-time/-/big-time-2.0.0.tgz", 78 | "integrity": "sha512-OXsmBxlRLwUc65MLta2EOyMTLcjZQkxHkJ81lVPeyVqZag8zhUfKRYIbF3E/IW/LWR8kf8a1GlRYkBXKVGqJOw==" 79 | }, 80 | "bounce": { 81 | "version": "1.2.0", 82 | "resolved": "https://registry.npmjs.org/bounce/-/bounce-1.2.0.tgz", 83 | "integrity": "sha512-8syCGe8B2/WC53118/F/tFy5aW00j+eaGPXmAUP7iBhxc+EBZZxS1vKelWyBCH6IqojgS2t1gF0glH30qAJKEw==", 84 | "requires": { 85 | "boom": "7.1.1", 86 | "hoek": "5.0.2" 87 | }, 88 | "dependencies": { 89 | "boom": { 90 | "version": "7.1.1", 91 | "resolved": "https://registry.npmjs.org/boom/-/boom-7.1.1.tgz", 92 | "integrity": "sha512-qwEARHTliqgEQiVkzKkkbLt3q0vRPIW60VRZ8zRnbjsm7INkPe9NxfAYDDYLZOdhxyUHa1gIe639Cx7t6RH/4A==", 93 | "requires": { 94 | "hoek": "5.0.2" 95 | } 96 | }, 97 | "hoek": { 98 | "version": "5.0.2", 99 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.2.tgz", 100 | "integrity": "sha512-NA10UYP9ufCtY2qYGkZktcQXwVyYK4zK0gkaFSB96xhtlo6V8tKXdQgx8eHolQTRemaW0uLn8BhjhwqrOU+QLQ==" 101 | } 102 | } 103 | }, 104 | "hapi": { 105 | "version": "17.2.0", 106 | "resolved": "https://registry.npmjs.org/hapi/-/hapi-17.2.0.tgz", 107 | "integrity": "sha512-zw2tqNimjT+qglgUNGNpeweHJ5To1xUcJcfGKsG5dWiTzwkEZtmtHJ8mBIvxuuZ3Buu4xkAGj0yWrrR95FVqQQ==", 108 | "requires": { 109 | "accept": "3.0.2", 110 | "ammo": "3.0.0", 111 | "boom": "7.1.1", 112 | "bounce": "1.2.0", 113 | "call": "5.0.1", 114 | "catbox": "10.0.2", 115 | "catbox-memory": "3.1.1", 116 | "heavy": "6.1.0", 117 | "hoek": "5.0.2", 118 | "joi": "13.0.2", 119 | "mimos": "4.0.0", 120 | "podium": "3.1.2", 121 | "shot": "4.0.4", 122 | "statehood": "6.0.5", 123 | "subtext": "6.0.7", 124 | "teamwork": "3.0.1", 125 | "topo": "3.0.0" 126 | }, 127 | "dependencies": { 128 | "accept": { 129 | "version": "3.0.2", 130 | "resolved": "https://registry.npmjs.org/accept/-/accept-3.0.2.tgz", 131 | "integrity": "sha512-bghLXFkCOsC1Y2TZ51etWfKDs6q249SAoHTZVfzWWdlZxoij+mgkj9AmUJWQpDY48TfnrTDIe43Xem4zdMe7mQ==", 132 | "requires": { 133 | "boom": "7.1.1", 134 | "hoek": "5.0.2" 135 | } 136 | }, 137 | "ammo": { 138 | "version": "3.0.0", 139 | "resolved": "https://registry.npmjs.org/ammo/-/ammo-3.0.0.tgz", 140 | "integrity": "sha512-6yoz9MXYV9sgCHrwprHWPxBaJ9/roQRfXzS//4JCNgKfPYcghFNwJQKBt6vWOoSGGRHsP6qsLJ+xtKStKJWdLQ==", 141 | "requires": { 142 | "boom": "6.0.0", 143 | "hoek": "5.0.2" 144 | }, 145 | "dependencies": { 146 | "boom": { 147 | "version": "6.0.0", 148 | "resolved": "https://registry.npmjs.org/boom/-/boom-6.0.0.tgz", 149 | "integrity": "sha512-LYLa8BmiiOWjvxTMVh73lcZzd2E5yczrKvxAny1UuzO2tkarLrw4tdp3rdfmus3+YfKcZP0vRSM3Obh+fGK6eA==", 150 | "requires": { 151 | "hoek": "5.0.2" 152 | } 153 | } 154 | } 155 | }, 156 | "b64": { 157 | "version": "4.0.0", 158 | "resolved": "https://registry.npmjs.org/b64/-/b64-4.0.0.tgz", 159 | "integrity": "sha512-EhmUQodKB0sdzPPrbIWbGqA5cQeTWxYrAgNeeT1rLZWtD3tbNTnphz8J4vkXI3cPgBNlXBjzEbzDzq0Nwi4f9A==" 160 | }, 161 | "boom": { 162 | "version": "7.1.1", 163 | "resolved": "https://registry.npmjs.org/boom/-/boom-7.1.1.tgz", 164 | "integrity": "sha512-qwEARHTliqgEQiVkzKkkbLt3q0vRPIW60VRZ8zRnbjsm7INkPe9NxfAYDDYLZOdhxyUHa1gIe639Cx7t6RH/4A==", 165 | "requires": { 166 | "hoek": "5.0.2" 167 | } 168 | }, 169 | "call": { 170 | "version": "5.0.1", 171 | "resolved": "https://registry.npmjs.org/call/-/call-5.0.1.tgz", 172 | "integrity": "sha512-ollfFPSshiuYLp7AsrmpkQJ/PxCi6AzV81rCjBwWhyF2QGyUY/vPDMzoh4aUcWyucheRglG2LaS5qkIEfLRh6A==", 173 | "requires": { 174 | "boom": "7.1.1", 175 | "hoek": "5.0.2" 176 | } 177 | }, 178 | "catbox": { 179 | "version": "10.0.2", 180 | "resolved": "https://registry.npmjs.org/catbox/-/catbox-10.0.2.tgz", 181 | "integrity": "sha512-cTQTQeKMhWHU0lX8CADE3g1koGJu+AlcWFzAjMX/8P+XbkScGYw3tJsQpe2Oh8q68vOQbOLacz9k+6V/F3Z9DA==", 182 | "requires": { 183 | "boom": "7.1.1", 184 | "bounce": "1.2.0", 185 | "hoek": "5.0.2", 186 | "joi": "13.0.2" 187 | } 188 | }, 189 | "catbox-memory": { 190 | "version": "3.1.1", 191 | "resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-3.1.1.tgz", 192 | "integrity": "sha512-fl6TI/uneeUb9NGClKWZWkpCZQrkPmuVz/Jaqqb15vqW6KGfJ/vMP/ZMp8VgAkyTrrRvFHbFcS67sbU7EkvbhQ==", 193 | "requires": { 194 | "big-time": "2.0.0", 195 | "boom": "7.1.1", 196 | "hoek": "5.0.2" 197 | } 198 | }, 199 | "content": { 200 | "version": "4.0.3", 201 | "resolved": "https://registry.npmjs.org/content/-/content-4.0.3.tgz", 202 | "integrity": "sha512-BrMfT1xXZHaXyPT/sneXc3IQzh8uL15JWV1R5tU0xo4sBGjF7BN+IRi9WoQLSbfNEs7bJ3E69rjxBKg/RL7lOQ==", 203 | "requires": { 204 | "boom": "7.1.1" 205 | } 206 | }, 207 | "cryptiles": { 208 | "version": "4.1.1", 209 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.1.tgz", 210 | "integrity": "sha512-YuQUPbcOmaZsdvxJZ25DCA1W+lLIRoPJKBDKin+St1RCYEERSfoe1d25B1MvWNHN3e8SpFSVsqYvEUjp8J9H2w==", 211 | "requires": { 212 | "boom": "7.1.1" 213 | } 214 | }, 215 | "heavy": { 216 | "version": "6.1.0", 217 | "resolved": "https://registry.npmjs.org/heavy/-/heavy-6.1.0.tgz", 218 | "integrity": "sha512-TKS9DC9NOTGulHQI31Lx+bmeWmNOstbJbGMiN3pX6bF+Zc2GKSpbbym4oasNnB6yPGkqJ9TQXXYDGohqNSJRxA==", 219 | "requires": { 220 | "boom": "7.1.1", 221 | "hoek": "5.0.2", 222 | "joi": "13.0.2" 223 | } 224 | }, 225 | "hoek": { 226 | "version": "5.0.2", 227 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.2.tgz", 228 | "integrity": "sha512-NA10UYP9ufCtY2qYGkZktcQXwVyYK4zK0gkaFSB96xhtlo6V8tKXdQgx8eHolQTRemaW0uLn8BhjhwqrOU+QLQ==" 229 | }, 230 | "iron": { 231 | "version": "5.0.4", 232 | "resolved": "https://registry.npmjs.org/iron/-/iron-5.0.4.tgz", 233 | "integrity": "sha512-7iQ5/xFMIYaNt9g2oiNiWdhrOTdRUMFaWENUd0KghxwPUhrIH8DUY8FEyLNTTzf75jaII+jMexLdY/2HfV61RQ==", 234 | "requires": { 235 | "boom": "7.1.1", 236 | "cryptiles": "4.1.1", 237 | "hoek": "5.0.2" 238 | } 239 | }, 240 | "isemail": { 241 | "version": "3.0.0", 242 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.0.0.tgz", 243 | "integrity": "sha512-rz0ng/c+fX+zACpLgDB8fnUQ845WSU06f4hlhk4K8TJxmR6f5hyvitu9a9JdMD7aq/P4E0XdG1uaab2OiXgHlA==", 244 | "requires": { 245 | "punycode": "2.1.0" 246 | } 247 | }, 248 | "joi": { 249 | "version": "13.0.2", 250 | "resolved": "https://registry.npmjs.org/joi/-/joi-13.0.2.tgz", 251 | "integrity": "sha512-kVka3LaHQyENvcMW4WJPSepGM43oCofcKxfs9HbbKd/FrwBAAt4lNNTPKOzSMmV53GIspmNO4U3O2TzoGvxxCA==", 252 | "requires": { 253 | "hoek": "5.0.2", 254 | "isemail": "3.0.0", 255 | "topo": "3.0.0" 256 | } 257 | }, 258 | "mimos": { 259 | "version": "4.0.0", 260 | "resolved": "https://registry.npmjs.org/mimos/-/mimos-4.0.0.tgz", 261 | "integrity": "sha512-JvlvRLqGIlk+AYypWrbrDmhsM+6JVx/xBM5S3AMwTBz1trPCEoPN/swO2L4Wu653fL7oJdgk8DMQyG/Gq3JkZg==", 262 | "requires": { 263 | "hoek": "5.0.2", 264 | "mime-db": "1.32.0" 265 | } 266 | }, 267 | "nigel": { 268 | "version": "3.0.0", 269 | "resolved": "https://registry.npmjs.org/nigel/-/nigel-3.0.0.tgz", 270 | "integrity": "sha512-ufFVFCe1zS/pfIQzQNa5uJxB8v8IcVTUn1zyPvQwb4CQGRxxBfdQPSXpEnI6ZzIwbV5L+GuAoRhYgcVSvTO7fA==", 271 | "requires": { 272 | "hoek": "5.0.2", 273 | "vise": "3.0.0" 274 | } 275 | }, 276 | "pez": { 277 | "version": "4.0.1", 278 | "resolved": "https://registry.npmjs.org/pez/-/pez-4.0.1.tgz", 279 | "integrity": "sha512-0c/SoW5MY7lPdc5U1Q/ixyjLZbluGWJonHVmn4mKwSq7vgO9+a9WzoCopHubIwkot6Q+fevNVElaA+1M9SqHrA==", 280 | "requires": { 281 | "b64": "4.0.0", 282 | "boom": "7.1.1", 283 | "content": "4.0.3", 284 | "hoek": "5.0.2", 285 | "nigel": "3.0.0" 286 | } 287 | }, 288 | "podium": { 289 | "version": "3.1.2", 290 | "resolved": "https://registry.npmjs.org/podium/-/podium-3.1.2.tgz", 291 | "integrity": "sha512-18VrjJAduIdPv7d9zWsfmKxTj3cQTYC5Pv5gtKxcWujYBpGbV+mhNSPYhlHW5xeWoazYyKfB9FEsPT12r5rY1A==", 292 | "requires": { 293 | "hoek": "5.0.2", 294 | "joi": "13.0.2" 295 | } 296 | }, 297 | "shot": { 298 | "version": "4.0.4", 299 | "resolved": "https://registry.npmjs.org/shot/-/shot-4.0.4.tgz", 300 | "integrity": "sha512-V8wHSJSNqt8ZIgdbTQCFIrp5BwBH+tsFLNBL1REmkFN/0PJdmzUBQscZqsbdSvdLc+Qxq7J5mcwzai66vs3ozA==", 301 | "requires": { 302 | "hoek": "5.0.2", 303 | "joi": "13.0.2" 304 | } 305 | }, 306 | "statehood": { 307 | "version": "6.0.5", 308 | "resolved": "https://registry.npmjs.org/statehood/-/statehood-6.0.5.tgz", 309 | "integrity": "sha512-HPa8qT5sGTBVn1Fc9czBYR1oo7gBaay3ysnb04cvcF80YrDIV7880KpjmMj54j7CrFuQFfgMRb44QCRxRmAdTg==", 310 | "requires": { 311 | "boom": "7.1.1", 312 | "bounce": "1.2.0", 313 | "cryptiles": "4.1.1", 314 | "hoek": "5.0.2", 315 | "iron": "5.0.4", 316 | "joi": "13.0.2" 317 | } 318 | }, 319 | "subtext": { 320 | "version": "6.0.7", 321 | "resolved": "https://registry.npmjs.org/subtext/-/subtext-6.0.7.tgz", 322 | "integrity": "sha512-IcJUvRjeR+NB437Iq+LORFNJW4L6Knqkj3oQrBrkdhIaS2VKJvx/9aYEq7vi+PEx5/OuehOL/40SkSZotLi/MA==", 323 | "requires": { 324 | "boom": "7.1.1", 325 | "content": "4.0.3", 326 | "hoek": "5.0.2", 327 | "pez": "4.0.1", 328 | "wreck": "14.0.2" 329 | } 330 | }, 331 | "topo": { 332 | "version": "3.0.0", 333 | "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz", 334 | "integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==", 335 | "requires": { 336 | "hoek": "5.0.2" 337 | } 338 | }, 339 | "vise": { 340 | "version": "3.0.0", 341 | "resolved": "https://registry.npmjs.org/vise/-/vise-3.0.0.tgz", 342 | "integrity": "sha512-kBFZLmiL1Vm3rHXphkhvvAcsjgeQXRrOFCbJb0I50YZZP4HGRNH+xGzK3matIMcpbsfr3I02u9odj4oCD0TWgA==", 343 | "requires": { 344 | "hoek": "5.0.2" 345 | } 346 | }, 347 | "wreck": { 348 | "version": "14.0.2", 349 | "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.0.2.tgz", 350 | "integrity": "sha512-QCm3omWNJUseqrSzwX2QZi1rBbmCfbFHJAXputLLyZ37VSiFnSYQB0ms/mPnSvrlIu7GVm89Y/gBNhSY26uVIQ==", 351 | "requires": { 352 | "boom": "7.1.1", 353 | "hoek": "5.0.2" 354 | } 355 | } 356 | } 357 | }, 358 | "hapi-auth-cookie": { 359 | "version": "8.0.0", 360 | "resolved": "https://registry.npmjs.org/hapi-auth-cookie/-/hapi-auth-cookie-8.0.0.tgz", 361 | "integrity": "sha512-RYFbjeNUIeKgoYA8yZQVFMfyR2OvtNpYiMrasz7pgq9rKs+srIHPoLSOo17qT//pvKp8UEZ4lIsDWxQ5kXNhww==", 362 | "requires": { 363 | "boom": "7.1.1", 364 | "bounce": "1.2.0", 365 | "hoek": "5.0.2", 366 | "joi": "13.0.2" 367 | }, 368 | "dependencies": { 369 | "boom": { 370 | "version": "7.1.1", 371 | "resolved": "https://registry.npmjs.org/boom/-/boom-7.1.1.tgz", 372 | "integrity": "sha512-qwEARHTliqgEQiVkzKkkbLt3q0vRPIW60VRZ8zRnbjsm7INkPe9NxfAYDDYLZOdhxyUHa1gIe639Cx7t6RH/4A==", 373 | "requires": { 374 | "hoek": "5.0.2" 375 | } 376 | }, 377 | "hoek": { 378 | "version": "5.0.2", 379 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.2.tgz", 380 | "integrity": "sha512-NA10UYP9ufCtY2qYGkZktcQXwVyYK4zK0gkaFSB96xhtlo6V8tKXdQgx8eHolQTRemaW0uLn8BhjhwqrOU+QLQ==" 381 | }, 382 | "isemail": { 383 | "version": "3.0.0", 384 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.0.0.tgz", 385 | "integrity": "sha512-rz0ng/c+fX+zACpLgDB8fnUQ845WSU06f4hlhk4K8TJxmR6f5hyvitu9a9JdMD7aq/P4E0XdG1uaab2OiXgHlA==", 386 | "requires": { 387 | "punycode": "2.1.0" 388 | } 389 | }, 390 | "joi": { 391 | "version": "13.0.2", 392 | "resolved": "https://registry.npmjs.org/joi/-/joi-13.0.2.tgz", 393 | "integrity": "sha512-kVka3LaHQyENvcMW4WJPSepGM43oCofcKxfs9HbbKd/FrwBAAt4lNNTPKOzSMmV53GIspmNO4U3O2TzoGvxxCA==", 394 | "requires": { 395 | "hoek": "5.0.2", 396 | "isemail": "3.0.0", 397 | "topo": "3.0.0" 398 | } 399 | }, 400 | "topo": { 401 | "version": "3.0.0", 402 | "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz", 403 | "integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==", 404 | "requires": { 405 | "hoek": "5.0.2" 406 | } 407 | } 408 | } 409 | }, 410 | "mime-db": { 411 | "version": "1.32.0", 412 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.32.0.tgz", 413 | "integrity": "sha512-+ZWo/xZN40Tt6S+HyakUxnSOgff+JEdaneLWIm0Z6LmpCn5DMcZntLyUY5c/rTDog28LhXLKOUZKoTxTCAdBVw==" 414 | }, 415 | "punycode": { 416 | "version": "2.1.0", 417 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", 418 | "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" 419 | }, 420 | "teamwork": { 421 | "version": "3.0.1", 422 | "resolved": "https://registry.npmjs.org/teamwork/-/teamwork-3.0.1.tgz", 423 | "integrity": "sha512-hEkJIpDOfOYe9NYaLFk00zQbzZeKNCY8T2pRH3I13Y1mJwxaSQ6NEsjY5rCp+11ezCiZpWGoGFTbOuhg4qKevQ==" 424 | } 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /github-oauth-with-hapi-v17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-oauth-with-hapi-v17", 3 | "version": "0.0.1", 4 | "main": "server.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "start": "node server.js" 8 | }, 9 | "dependencies": { 10 | "bell": "github:makeomatic/bell#hapi17", 11 | "hapi": "^17.2.0", 12 | "hapi-auth-cookie": "^8.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /github-oauth-with-hapi-v17/server.js: -------------------------------------------------------------------------------- 1 | // # [GitHub OAuth with Hapi v17](https://github.com/resources/snippets/tree/master/github-oauth-with-hapi-v16) 2 | // 3 | // - `npm init -y` 4 | // - `npm install hapi hapi-auth-cookie github:makeomatic/bell#hapi17 --save` 5 | // - generate a session key: 6 | // `export SESSION_KEY=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")` 7 | // - go to github.com > Settings > Developer Settings > OAuth Apps and add a new app 8 | // - you can use your personal web page for the application URL and a temporary callback URL 9 | // - you can change the callback URL later 10 | // - set the client ID: `export GITHUB_CLIENT_ID=YOUR_CLIENT_ID` 11 | // - set the client secret: `export GITHUB_CLIENT_SECRET=YOUR_CLIENT_SECRET` 12 | // - test with ngrok: 13 | // - run `npm start` 14 | // - in a new console tab, run `brew cask install ngrok` 15 | // - run `ngrok http 3000` 16 | // - set the callback URL to https://yourngrokurl.ngrok.io/auth/github on the GitHub OAuth app page 17 | // - open https://yourngrokurl.ngrok.io/ in your browser 18 | // - deploy with now: 19 | // - set up https://zeit.co/now if you haven't already 20 | // - run `now`: 21 | // now -e SESSION_KEY=$SESSION_KEY \ 22 | // -e GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID \ 23 | // -e GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET 24 | // - run `now alias set https://auto-generated-subdomain.now.sh your-now-subdomain` 25 | // - update the callback URL to https://your-now-subdomain.now.sh/auth/github on the GitHub OAuth app page 26 | // - open https://your-now-subdomain.now.sh/ in your browser 27 | 'use strict'; 28 | 29 | const Hapi = require('hapi'); 30 | const HapiAuthCookie = require('hapi-auth-cookie'); 31 | const Bell = require('bell'); 32 | 33 | async function start() { 34 | const server = Hapi.server({ 35 | port: process.env.PORT || 3000 36 | }); 37 | 38 | await server.register(HapiAuthCookie); 39 | await server.register(Bell); 40 | 41 | server.auth.strategy('session', 'cookie', { 42 | password: process.env.SESSION_KEY, 43 | redirectTo: '/', 44 | }); 45 | 46 | server.auth.strategy('github', 'bell', { 47 | provider: 'github', 48 | scope: ['user:email'], 49 | password: process.env.SESSION_KEY, 50 | clientId: process.env.GITHUB_CLIENT_ID, 51 | clientSecret: process.env.GITHUB_CLIENT_SECRET, 52 | forceHttps: true, // needed to use ngrok when testing locally 53 | }); 54 | 55 | server.route({ 56 | method: 'GET', 57 | path: '/', 58 | config: { 59 | auth: {strategy: 'session', mode: 'try'}, 60 | plugins: {'hapi-auth-cookie': {redirectTo: false}}, 61 | handler: (request, h) => { 62 | if (request.auth.credentials) { 63 | const {username, email} = request.auth.credentials; 64 | return `
${JSON.stringify({username, email}, null, 2)}
65 |

Go to /secret to see a protected page!

`; 66 | } else { 67 | return 'Go to /auth/github to sign in!'; 68 | } 69 | } 70 | } 71 | }); 72 | 73 | server.route({ 74 | method: ['GET', 'POST'], 75 | path: '/auth/github', 76 | config: { 77 | auth: 'github', 78 | handler: async (request, h) => { 79 | if (! request.auth.isAuthenticated) { 80 | return `Auth failed: ${request.auth.error.message}`; 81 | } 82 | 83 | const {username, email} = request.auth.credentials.profile; 84 | request.cookieAuth.set({username, email}); 85 | 86 | return h.redirect('/'); 87 | } 88 | } 89 | }); 90 | 91 | server.route({ 92 | method: 'GET', 93 | path: '/secret', 94 | config: { 95 | auth: 'session', 96 | handler: (request, h) => { 97 | return 'You should only see this when logged in.'; 98 | } 99 | } 100 | }); 101 | 102 | server.route({ 103 | method: 'GET', 104 | path: '/logout', 105 | handler: (request, h) => { 106 | request.cookieAuth.clear(); 107 | return h.redirect('/'); 108 | } 109 | }); 110 | 111 | await server.start(); 112 | console.log(`Server running at: ${server.info.uri}`); 113 | } 114 | 115 | start().catch(err => { 116 | console.error(err); 117 | process.exit(1); 118 | }); -------------------------------------------------------------------------------- /gitlab-oauth-with-hapi-v16/README.md: -------------------------------------------------------------------------------- 1 | # [GitLab OAuth with Hapi v16]tps://github.com/resources/snippets/tree/master/gitlab-oauth-with-hapi-v16) 2 | 3 | - `npm init -y` 4 | - `npm install hapi@16 hapi-auth-cookie@7 bell@8 --save` 5 | - generate a session key: 6 | `export SESSION_KEY=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")` 7 | - Log into a GitLab account 8 | - To create your own GitLab server, here is [a walkthrough]tps://github.com/resources/walkthroughs/blob/master/gitlab.md) 9 | - Or create an account on GitLab.com 10 | - Go to Settings > Applications and add a new app (use the read_user permissions if just using for hentication) 11 | - use `https://yourdomain.example.com/auth/gitlab` as your redirect URI 12 | - set the application ID: `export GITLAB_APPLICATION_ID=YOUR_APPLICATION_ID` 13 | - set the secret: `export GITLAB_SECRET=YOUR_SECRET` 14 | - set the URI of your gitlab: `export GITLAB_URI=https://gitlab.example.com` (use `https://gitlab.com` using gitlab.com) 15 | - test with ngrok: 16 | - run `npm start` 17 | - in a new console tab, run `brew cask install ngrok` 18 | - run `ngrok http 3000` 19 | - set the callback URL to https://yourngrokurl.ngrok.io/auth/gitlab on the OAuth app page 20 | - open https://yourngrokurl.ngrok.io/ in your browser 21 | - deploy with now: 22 | - set up https://zeit.co/now if you haven't already 23 | - run `now`: 24 | now -e SESSION_KEY=$SESSION_KEY \ 25 | -e GITLAB_APPLICATION_ID=$GITLAB_APPLICATION_ID \ 26 | -e GITLAB_SECRET=$GITLAB_SECRET \ 27 | -e GITLAB_URI=$GITLAB_URI 28 | - run `now alias set https://auto-generated-subdomain.now.sh your-now-subdomain` 29 | - update the callback URL to https://your-now-subdomain.now.sh/auth/gitlab on the GitLab OAuth app page 30 | - open https://your-now-subdomain.now.sh/ in your browser 31 | ``` js 32 | 'use strict'; 33 | 34 | const Hapi = require('hapi'); 35 | const HapiAuthCookie = require('hapi-auth-cookie'); 36 | const Bell = require('bell'); 37 | 38 | const server = new Hapi.Server(); 39 | 40 | server.connection({port: process.env.PORT || 3000}); 41 | 42 | async function start() { 43 | await server.register(HapiAuthCookie); 44 | await server.register(Bell); 45 | 46 | server.auth.strategy('session', 'cookie', { 47 | password: process.env.SESSION_KEY, 48 | redirectTo: '/', 49 | }); 50 | 51 | server.auth.strategy('gitlab', 'bell', { 52 | provider: 'gitlab', 53 | scope: ['read_user'], 54 | password: process.env.SESSION_KEY, 55 | config: { 56 | uri: process.env.GITLAB_URI 57 | }, 58 | clientId: process.env.GITLAB_APPLICATION_ID, 59 | clientSecret: process.env.GITLAB_SECRET, 60 | forceHttps: true, // needed to use ngrok when testing locally 61 | }); 62 | 63 | server.route({ 64 | method: 'GET', 65 | path: '/', 66 | config: { 67 | auth: {strategy: 'session', mode: 'try'}, 68 | plugins: {'hapi-auth-cookie': {redirectTo: false}}, 69 | handler: (request, reply) => { 70 | if (request.auth.credentials) { 71 | const {username, email} = request.auth.credentials; 72 | reply(`
${JSON.stringify({username, email}, null, 2)}
73 |

Go to /secret to see a protected page!

`); 74 | } else { 75 | reply('Go to /auth/gitlab to sign in!'); 76 | } 77 | } 78 | } 79 | }); 80 | 81 | server.route({ 82 | method: ['GET', 'POST'], 83 | path: '/auth/gitlab', 84 | config: { 85 | auth: 'gitlab', 86 | handler: (request, reply) => { 87 | if (! request.auth.isAuthenticated) { 88 | return reply(`Auth failed: ${request.auth.error.message}`); 89 | } 90 | 91 | const {username, email} = request.auth.credentials.profile; 92 | request.cookieAuth.set({username, email}); 93 | 94 | return reply.redirect('/'); 95 | } 96 | } 97 | }); 98 | 99 | server.route({ 100 | method: 'GET', 101 | path: '/secret', 102 | config: { 103 | auth: 'session', 104 | handler: (request, reply) => { 105 | reply('You should only see this when logged in.'); 106 | } 107 | } 108 | }); 109 | 110 | server.route({ 111 | method: 'GET', 112 | path: '/logout', 113 | handler: (request, reply) => { 114 | request.cookieAuth.clear(); 115 | reply.redirect('/'); 116 | } 117 | }); 118 | 119 | await server.start(); 120 | } 121 | 122 | start().then(() => { 123 | console.log(`Server running at: ${server.info.uri}`); 124 | }).catch(err => { 125 | console.error(err); 126 | process.exit(1); 127 | }); 128 | ``` -------------------------------------------------------------------------------- /gitlab-oauth-with-hapi-v16/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitlab-oauth-with-hapi-v16", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accept": { 8 | "version": "2.1.4", 9 | "resolved": "https://registry.npmjs.org/accept/-/accept-2.1.4.tgz", 10 | "integrity": "sha1-iHr1TO7lx/RDBGGXHsQAxh0JrLs=", 11 | "requires": { 12 | "boom": "5.2.0", 13 | "hoek": "4.2.0" 14 | }, 15 | "dependencies": { 16 | "boom": { 17 | "version": "5.2.0", 18 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 19 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 20 | "requires": { 21 | "hoek": "4.2.0" 22 | } 23 | } 24 | } 25 | }, 26 | "ammo": { 27 | "version": "2.0.4", 28 | "resolved": "https://registry.npmjs.org/ammo/-/ammo-2.0.4.tgz", 29 | "integrity": "sha1-v4CqshFpjqePY+9efxE91dnokX8=", 30 | "requires": { 31 | "boom": "5.2.0", 32 | "hoek": "4.2.0" 33 | }, 34 | "dependencies": { 35 | "boom": { 36 | "version": "5.2.0", 37 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 38 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 39 | "requires": { 40 | "hoek": "4.2.0" 41 | } 42 | } 43 | } 44 | }, 45 | "b64": { 46 | "version": "3.0.3", 47 | "resolved": "https://registry.npmjs.org/b64/-/b64-3.0.3.tgz", 48 | "integrity": "sha512-Pbeh0i6OLubPJdIdCepn8ZQHwN2MWznZHbHABSTEfQ706ie+yuxNSaPdqX1xRatT6WanaS1EazMiSg0NUW2XxQ==" 49 | }, 50 | "bell": { 51 | "version": "8.9.0", 52 | "resolved": "https://registry.npmjs.org/bell/-/bell-8.9.0.tgz", 53 | "integrity": "sha512-tibCCgKaP9ahjGAJs/YDpAWWZyLmlvJfjMa7ElPA9/mkmCvswedvouI0DVRaa/1zfKqQ9GTy6Y2ZMhCfJbCPfQ==", 54 | "requires": { 55 | "boom": "4.2.0", 56 | "cryptiles": "3.1.2", 57 | "hoek": "4.2.0", 58 | "joi": "10.6.0", 59 | "wreck": "10.0.0" 60 | } 61 | }, 62 | "boom": { 63 | "version": "4.2.0", 64 | "resolved": "https://registry.npmjs.org/boom/-/boom-4.2.0.tgz", 65 | "integrity": "sha1-wadBdLEfu6Ij9hYtT9iFGhuCpTY=", 66 | "requires": { 67 | "hoek": "4.2.0" 68 | } 69 | }, 70 | "call": { 71 | "version": "4.0.2", 72 | "resolved": "https://registry.npmjs.org/call/-/call-4.0.2.tgz", 73 | "integrity": "sha1-33b19R7o3Ui4VqyEAPfmnm1zmcQ=", 74 | "requires": { 75 | "boom": "5.2.0", 76 | "hoek": "4.2.0" 77 | }, 78 | "dependencies": { 79 | "boom": { 80 | "version": "5.2.0", 81 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 82 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 83 | "requires": { 84 | "hoek": "4.2.0" 85 | } 86 | } 87 | } 88 | }, 89 | "catbox": { 90 | "version": "7.1.5", 91 | "resolved": "https://registry.npmjs.org/catbox/-/catbox-7.1.5.tgz", 92 | "integrity": "sha512-4fui5lELzqZ+9cnaAP/BcqXTH6LvWLBRtFhJ0I4FfgfXiSaZcf6k9m9dqOyChiTxNYtvLk7ZMYSf7ahMq3bf5A==", 93 | "requires": { 94 | "boom": "5.2.0", 95 | "hoek": "4.2.0", 96 | "joi": "10.6.0" 97 | }, 98 | "dependencies": { 99 | "boom": { 100 | "version": "5.2.0", 101 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 102 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 103 | "requires": { 104 | "hoek": "4.2.0" 105 | } 106 | } 107 | } 108 | }, 109 | "catbox-memory": { 110 | "version": "2.0.4", 111 | "resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-2.0.4.tgz", 112 | "integrity": "sha1-Qz4lWQLK9UIz0ShkKcj03xToItU=", 113 | "requires": { 114 | "hoek": "4.2.0" 115 | } 116 | }, 117 | "content": { 118 | "version": "3.0.6", 119 | "resolved": "https://registry.npmjs.org/content/-/content-3.0.6.tgz", 120 | "integrity": "sha512-tyl3fRp8jOHsQR0X9vrIy0mKQccv0tA9/RlvLl514eA7vHOJr/TnmMTpgQjInwbeW9IOQVy0OECGAuQNUa0nnQ==", 121 | "requires": { 122 | "boom": "5.2.0" 123 | }, 124 | "dependencies": { 125 | "boom": { 126 | "version": "5.2.0", 127 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 128 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 129 | "requires": { 130 | "hoek": "4.2.0" 131 | } 132 | } 133 | } 134 | }, 135 | "cryptiles": { 136 | "version": "3.1.2", 137 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", 138 | "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", 139 | "requires": { 140 | "boom": "5.2.0" 141 | }, 142 | "dependencies": { 143 | "boom": { 144 | "version": "5.2.0", 145 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 146 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 147 | "requires": { 148 | "hoek": "4.2.0" 149 | } 150 | } 151 | } 152 | }, 153 | "hapi": { 154 | "version": "16.6.2", 155 | "resolved": "https://registry.npmjs.org/hapi/-/hapi-16.6.2.tgz", 156 | "integrity": "sha512-DBeIsge8nn3rBSFGX/btOwwkkVIMTuWHIkkiWtRAq8IHxhBfmVSewPm4BprU50PQjncQFw44JTN77l/pMKVHlA==", 157 | "requires": { 158 | "accept": "2.1.4", 159 | "ammo": "2.0.4", 160 | "boom": "5.2.0", 161 | "call": "4.0.2", 162 | "catbox": "7.1.5", 163 | "catbox-memory": "2.0.4", 164 | "cryptiles": "3.1.2", 165 | "heavy": "4.0.4", 166 | "hoek": "4.2.0", 167 | "iron": "4.0.5", 168 | "items": "2.1.1", 169 | "joi": "11.4.0", 170 | "mimos": "3.0.3", 171 | "podium": "1.3.0", 172 | "shot": "3.4.2", 173 | "statehood": "5.0.3", 174 | "subtext": "5.0.0", 175 | "topo": "2.0.2" 176 | }, 177 | "dependencies": { 178 | "boom": { 179 | "version": "5.2.0", 180 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 181 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 182 | "requires": { 183 | "hoek": "4.2.0" 184 | } 185 | }, 186 | "isemail": { 187 | "version": "3.0.0", 188 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.0.0.tgz", 189 | "integrity": "sha512-rz0ng/c+fX+zACpLgDB8fnUQ845WSU06f4hlhk4K8TJxmR6f5hyvitu9a9JdMD7aq/P4E0XdG1uaab2OiXgHlA==", 190 | "requires": { 191 | "punycode": "2.1.0" 192 | } 193 | }, 194 | "joi": { 195 | "version": "11.4.0", 196 | "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", 197 | "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", 198 | "requires": { 199 | "hoek": "4.2.0", 200 | "isemail": "3.0.0", 201 | "topo": "2.0.2" 202 | } 203 | } 204 | } 205 | }, 206 | "hapi-auth-cookie": { 207 | "version": "7.0.0", 208 | "resolved": "https://registry.npmjs.org/hapi-auth-cookie/-/hapi-auth-cookie-7.0.0.tgz", 209 | "integrity": "sha1-G7kTDYWrDv4C999RjoZIZ2FqSaQ=", 210 | "requires": { 211 | "boom": "3.2.2", 212 | "hoek": "4.2.0", 213 | "joi": "8.4.2" 214 | }, 215 | "dependencies": { 216 | "boom": { 217 | "version": "3.2.2", 218 | "resolved": "https://registry.npmjs.org/boom/-/boom-3.2.2.tgz", 219 | "integrity": "sha1-DwzF0ErcUAO4x9cfQsynJx/vDng=", 220 | "requires": { 221 | "hoek": "4.2.0" 222 | } 223 | }, 224 | "joi": { 225 | "version": "8.4.2", 226 | "resolved": "https://registry.npmjs.org/joi/-/joi-8.4.2.tgz", 227 | "integrity": "sha1-vXd0ZY/pkFjYmU7R1LmWJITruFk=", 228 | "requires": { 229 | "hoek": "4.2.0", 230 | "isemail": "2.2.1", 231 | "moment": "2.20.1", 232 | "topo": "2.0.2" 233 | } 234 | } 235 | } 236 | }, 237 | "heavy": { 238 | "version": "4.0.4", 239 | "resolved": "https://registry.npmjs.org/heavy/-/heavy-4.0.4.tgz", 240 | "integrity": "sha1-NskTNsAMz+hSyqTRUwhjNc0vAOk=", 241 | "requires": { 242 | "boom": "5.2.0", 243 | "hoek": "4.2.0", 244 | "joi": "10.6.0" 245 | }, 246 | "dependencies": { 247 | "boom": { 248 | "version": "5.2.0", 249 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 250 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 251 | "requires": { 252 | "hoek": "4.2.0" 253 | } 254 | } 255 | } 256 | }, 257 | "hoek": { 258 | "version": "4.2.0", 259 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", 260 | "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" 261 | }, 262 | "iron": { 263 | "version": "4.0.5", 264 | "resolved": "https://registry.npmjs.org/iron/-/iron-4.0.5.tgz", 265 | "integrity": "sha1-TwQszri5c480a1mqc0yDqJvDFCg=", 266 | "requires": { 267 | "boom": "5.2.0", 268 | "cryptiles": "3.1.2", 269 | "hoek": "4.2.0" 270 | }, 271 | "dependencies": { 272 | "boom": { 273 | "version": "5.2.0", 274 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 275 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 276 | "requires": { 277 | "hoek": "4.2.0" 278 | } 279 | } 280 | } 281 | }, 282 | "isemail": { 283 | "version": "2.2.1", 284 | "resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz", 285 | "integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY=" 286 | }, 287 | "items": { 288 | "version": "2.1.1", 289 | "resolved": "https://registry.npmjs.org/items/-/items-2.1.1.tgz", 290 | "integrity": "sha1-i9FtnIOxlSneWuoyGsqtp4NkoZg=" 291 | }, 292 | "joi": { 293 | "version": "10.6.0", 294 | "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", 295 | "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", 296 | "requires": { 297 | "hoek": "4.2.0", 298 | "isemail": "2.2.1", 299 | "items": "2.1.1", 300 | "topo": "2.0.2" 301 | } 302 | }, 303 | "mime-db": { 304 | "version": "1.32.0", 305 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.32.0.tgz", 306 | "integrity": "sha512-+ZWo/xZN40Tt6S+HyakUxnSOgff+JEdaneLWIm0Z6LmpCn5DMcZntLyUY5c/rTDog28LhXLKOUZKoTxTCAdBVw==" 307 | }, 308 | "mimos": { 309 | "version": "3.0.3", 310 | "resolved": "https://registry.npmjs.org/mimos/-/mimos-3.0.3.tgz", 311 | "integrity": "sha1-uRCQcq03jCty9qAQHEPd+ys2ZB8=", 312 | "requires": { 313 | "hoek": "4.2.0", 314 | "mime-db": "1.32.0" 315 | } 316 | }, 317 | "moment": { 318 | "version": "2.20.1", 319 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", 320 | "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==" 321 | }, 322 | "nigel": { 323 | "version": "2.0.2", 324 | "resolved": "https://registry.npmjs.org/nigel/-/nigel-2.0.2.tgz", 325 | "integrity": "sha1-k6GGb7DFLYc5CqdeKxYfS1x15bE=", 326 | "requires": { 327 | "hoek": "4.2.0", 328 | "vise": "2.0.2" 329 | } 330 | }, 331 | "pez": { 332 | "version": "2.1.5", 333 | "resolved": "https://registry.npmjs.org/pez/-/pez-2.1.5.tgz", 334 | "integrity": "sha1-XsLMYlAMw+tCNtSkFM9aF7XrUAc=", 335 | "requires": { 336 | "b64": "3.0.3", 337 | "boom": "5.2.0", 338 | "content": "3.0.6", 339 | "hoek": "4.2.0", 340 | "nigel": "2.0.2" 341 | }, 342 | "dependencies": { 343 | "boom": { 344 | "version": "5.2.0", 345 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 346 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 347 | "requires": { 348 | "hoek": "4.2.0" 349 | } 350 | } 351 | } 352 | }, 353 | "podium": { 354 | "version": "1.3.0", 355 | "resolved": "https://registry.npmjs.org/podium/-/podium-1.3.0.tgz", 356 | "integrity": "sha512-ZIujqk1pv8bRZNVxwwwq0BhXilZ2udycQT3Kp8ah3f3TcTmVg7ILJsv/oLf47gRa2qeiP584lNq+pfvS9U3aow==", 357 | "requires": { 358 | "hoek": "4.2.0", 359 | "items": "2.1.1", 360 | "joi": "10.6.0" 361 | } 362 | }, 363 | "punycode": { 364 | "version": "2.1.0", 365 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", 366 | "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" 367 | }, 368 | "shot": { 369 | "version": "3.4.2", 370 | "resolved": "https://registry.npmjs.org/shot/-/shot-3.4.2.tgz", 371 | "integrity": "sha1-Hlw/bysmZJrcQvfrNQIUpaApHWc=", 372 | "requires": { 373 | "hoek": "4.2.0", 374 | "joi": "10.6.0" 375 | } 376 | }, 377 | "statehood": { 378 | "version": "5.0.3", 379 | "resolved": "https://registry.npmjs.org/statehood/-/statehood-5.0.3.tgz", 380 | "integrity": "sha512-YrPrCt10t3ImH/JMO5szSwX7sCm8HoqVl3VFLOa9EZ1g/qJx/ZmMhN+2uzPPB/vaU6hpkJpXxcBWsgIkkG+MXA==", 381 | "requires": { 382 | "boom": "5.2.0", 383 | "cryptiles": "3.1.2", 384 | "hoek": "4.2.0", 385 | "iron": "4.0.5", 386 | "items": "2.1.1", 387 | "joi": "10.6.0" 388 | }, 389 | "dependencies": { 390 | "boom": { 391 | "version": "5.2.0", 392 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 393 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 394 | "requires": { 395 | "hoek": "4.2.0" 396 | } 397 | } 398 | } 399 | }, 400 | "subtext": { 401 | "version": "5.0.0", 402 | "resolved": "https://registry.npmjs.org/subtext/-/subtext-5.0.0.tgz", 403 | "integrity": "sha512-2nXG1G1V+K64Z20cQII7k0s38J2DSycMXBLMAk9RXUFG0uAkAbLSVoa88croX9VhTdBCJbLAe9g6LmzKwpJhhQ==", 404 | "requires": { 405 | "boom": "5.2.0", 406 | "content": "3.0.6", 407 | "hoek": "4.2.0", 408 | "pez": "2.1.5", 409 | "wreck": "12.5.1" 410 | }, 411 | "dependencies": { 412 | "boom": { 413 | "version": "5.2.0", 414 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 415 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 416 | "requires": { 417 | "hoek": "4.2.0" 418 | } 419 | }, 420 | "wreck": { 421 | "version": "12.5.1", 422 | "resolved": "https://registry.npmjs.org/wreck/-/wreck-12.5.1.tgz", 423 | "integrity": "sha512-l5DUGrc+yDyIflpty1x9XuMj1ehVjC/dTbF3/BasOO77xk0EdEa4M/DuOY8W88MQDAD0fEDqyjc8bkIMHd2E9A==", 424 | "requires": { 425 | "boom": "5.2.0", 426 | "hoek": "4.2.0" 427 | } 428 | } 429 | } 430 | }, 431 | "topo": { 432 | "version": "2.0.2", 433 | "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", 434 | "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", 435 | "requires": { 436 | "hoek": "4.2.0" 437 | } 438 | }, 439 | "vise": { 440 | "version": "2.0.2", 441 | "resolved": "https://registry.npmjs.org/vise/-/vise-2.0.2.tgz", 442 | "integrity": "sha1-awjo+0y3bjpQzW3Q7DczjoEaDTk=", 443 | "requires": { 444 | "hoek": "4.2.0" 445 | } 446 | }, 447 | "wreck": { 448 | "version": "10.0.0", 449 | "resolved": "https://registry.npmjs.org/wreck/-/wreck-10.0.0.tgz", 450 | "integrity": "sha1-mKuIL4XhalJjMlB/EB9aeEEWIng=", 451 | "requires": { 452 | "boom": "4.2.0", 453 | "hoek": "4.2.0" 454 | } 455 | } 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /gitlab-oauth-with-hapi-v16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitlab-oauth-with-hapi-v16", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bell": "^8.9.0", 15 | "hapi": "^16.6.2", 16 | "hapi-auth-cookie": "^7.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gitlab-oauth-with-hapi-v16/server.js: -------------------------------------------------------------------------------- 1 | // # [GitLab OAuth with Hapi v16](https://github.com/resources/snippets/tree/master/gitlab-oauth-with-hapi-v16) 2 | // 3 | // - `npm init -y` 4 | // - `npm install hapi@16 hapi-auth-cookie@7 bell@8 --save` 5 | // - generate a session key: 6 | // `export SESSION_KEY=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")` 7 | // - Log into a GitLab account 8 | // - To create your own GitLab server, here is [a walkthrough](https://github.com/resources/walkthroughs/blob/master/gitlab.md) 9 | // - Or create an account on GitLab.com 10 | // - Go to Settings > Applications and add a new app (use the read_user permissions if just using for authentication) 11 | // - use `https://yourdomain.example.com/auth/gitlab` as your redirect URI 12 | // - set the application ID: `export GITLAB_APPLICATION_ID=YOUR_APPLICATION_ID` 13 | // - set the secret: `export GITLAB_SECRET=YOUR_SECRET` 14 | // - set the URI of your gitlab: `export GITLAB_URI=https://gitlab.example.com` (use `https://gitlab.com` if using gitlab.com) 15 | // - test with ngrok: 16 | // - run `npm start` 17 | // - in a new console tab, run `brew cask install ngrok` 18 | // - run `ngrok http 3000` 19 | // - set the callback URL to https://yourngrokurl.ngrok.io/auth/gitlab on the OAuth app page 20 | // - open https://yourngrokurl.ngrok.io/ in your browser 21 | // - deploy with now: 22 | // - set up https://zeit.co/now if you haven't already 23 | // - run `now`: 24 | // now -e SESSION_KEY=$SESSION_KEY \ 25 | // -e GITLAB_APPLICATION_ID=$GITLAB_APPLICATION_ID \ 26 | // -e GITLAB_SECRET=$GITLAB_SECRET \ 27 | // -e GITLAB_URI=$GITLAB_URI 28 | // - run `now alias set https://auto-generated-subdomain.now.sh your-now-subdomain` 29 | // - update the callback URL to https://your-now-subdomain.now.sh/auth/gitlab on the GitLab OAuth app page 30 | // - open https://your-now-subdomain.now.sh/ in your browser 31 | 'use strict'; 32 | 33 | const Hapi = require('hapi'); 34 | const HapiAuthCookie = require('hapi-auth-cookie'); 35 | const Bell = require('bell'); 36 | 37 | const server = new Hapi.Server(); 38 | 39 | server.connection({port: process.env.PORT || 3000}); 40 | 41 | async function start() { 42 | await server.register(HapiAuthCookie); 43 | await server.register(Bell); 44 | 45 | server.auth.strategy('session', 'cookie', { 46 | password: process.env.SESSION_KEY, 47 | redirectTo: '/', 48 | }); 49 | 50 | server.auth.strategy('gitlab', 'bell', { 51 | provider: 'gitlab', 52 | scope: ['read_user'], 53 | password: process.env.SESSION_KEY, 54 | config: { 55 | uri: process.env.GITLAB_URI 56 | }, 57 | clientId: process.env.GITLAB_APPLICATION_ID, 58 | clientSecret: process.env.GITLAB_SECRET, 59 | forceHttps: true, // needed to use ngrok when testing locally 60 | }); 61 | 62 | server.route({ 63 | method: 'GET', 64 | path: '/', 65 | config: { 66 | auth: {strategy: 'session', mode: 'try'}, 67 | plugins: {'hapi-auth-cookie': {redirectTo: false}}, 68 | handler: (request, reply) => { 69 | if (request.auth.credentials) { 70 | const {username, email} = request.auth.credentials; 71 | reply(`
${JSON.stringify({username, email}, null, 2)}
72 |

Go to /secret to see a protected page!

`); 73 | } else { 74 | reply('Go to /auth/gitlab to sign in!'); 75 | } 76 | } 77 | } 78 | }); 79 | 80 | server.route({ 81 | method: ['GET', 'POST'], 82 | path: '/auth/gitlab', 83 | config: { 84 | auth: 'gitlab', 85 | handler: (request, reply) => { 86 | if (! request.auth.isAuthenticated) { 87 | return reply(`Auth failed: ${request.auth.error.message}`); 88 | } 89 | 90 | const {username, email} = request.auth.credentials.profile; 91 | request.cookieAuth.set({username, email}); 92 | 93 | return reply.redirect('/'); 94 | } 95 | } 96 | }); 97 | 98 | server.route({ 99 | method: 'GET', 100 | path: '/secret', 101 | config: { 102 | auth: 'session', 103 | handler: (request, reply) => { 104 | reply('You should only see this when logged in.'); 105 | } 106 | } 107 | }); 108 | 109 | server.route({ 110 | method: 'GET', 111 | path: '/logout', 112 | handler: (request, reply) => { 113 | request.cookieAuth.clear(); 114 | reply.redirect('/'); 115 | } 116 | }); 117 | 118 | await server.start(); 119 | } 120 | 121 | start().then(() => { 122 | console.log(`Server running at: ${server.info.uri}`); 123 | }).catch(err => { 124 | console.error(err); 125 | process.exit(1); 126 | }); -------------------------------------------------------------------------------- /matrix-incoming-webhook/README.md: -------------------------------------------------------------------------------- 1 | # [Matrix Incoming Webhook][url] 2 | 3 | 1. Go to [riot.im][riot] and sign up for an account 4 | 2. Create a new channel 5 | 3. Invite `@_webhook:t2bot.io` to your room, or your own webhook user 6 | if you're running your own matrix server and webhook bridge. See 7 | [the webhook bridge][webhook-bridge] docs. Wait for Webhook Bridge 8 | to join (it will no longer appear as "invited" in the sidebar). 9 | This may take a while, or you may need to run your own Matrix 10 | server and webhook bridge. 11 | 4. Send the message `!webhook` to your room 12 | 5. Wait a little while for Webhook Bridge to send you a message. Try 13 | sending `!webhook` again. 14 | 6. When you get a message, grab the token at the end of the URL and 15 | set the environment variable: `export WEBHOOK_TOKEN=` 16 | 17 | [url]: https://github.com/resources/snippets/tree/master/matrix-incoming-webhook 18 | [riot]: https://riot.im/ 19 | [webhook-bridge]: https://github.com/turt2live/matrix-appservice-webhooks 20 | ``` js 21 | const axios = require('axios'); 22 | 23 | class Client { 24 | constructor({token, displayName, avatarUrl}) { 25 | Object.assign(this, {token, displayName, avatarUrl}); 26 | } 27 | 28 | async sendMessage(message) { 29 | await axios.post(`https://webhooks.t2bot.io/api/v1/matrix/hook/${this.token}`, { 30 | text: message, 31 | format: 'plain', 32 | displayName: this.displayName, 33 | avatarUrl: this.avatarUrl 34 | }); 35 | } 36 | } 37 | 38 | async function start() { 39 | const client = new Client({ 40 | token: process.env.WEBHOOK_TOKEN, 41 | displayName: 'example-bot', 42 | avatarUrl: 'https://robohash.org/example-bot' 43 | }); 44 | await client.sendMessage('[matrix] rocks!'); 45 | } 46 | 47 | start().catch(err => { console.error(err); }); 48 | ``` -------------------------------------------------------------------------------- /matrix-incoming-webhook/index.js: -------------------------------------------------------------------------------- 1 | // # [Matrix Incoming Webhooks][url] 2 | // 3 | // 1. Go to [riot.im][riot] and sign up for an account 4 | // 2. Create a new channel 5 | // 3. Invite `@_webhook:t2bot.io` to your room, or your own webhook user 6 | // if you're running your own matrix server and webhook bridge. See 7 | // [the webhook bridge][webhook-bridge] docs. Wait for Webhook Bridge 8 | // to join (it will no longer appear as "invited" in the sidebar). 9 | // This may take a while, or you may need to run your own Matrix 10 | // server and webhook bridge. 11 | // 4. Send the message `!webhook` to your room 12 | // 5. Wait a little while for Webhook Bridge to send you a message. Try 13 | // sending `!webhook` again. 14 | // 6. When you get a message, grab the token at the end of the URL and 15 | // set the environment variable: `export WEBHOOK_TOKEN=` 16 | // 17 | // [riot]: https://riot.im/ 18 | // [webhook-bridge]: https://github.com/turt2live/matrix-appservice-webhooks 19 | const axios = require('axios'); 20 | 21 | class Client { 22 | constructor({token, displayName, avatarUrl}) { 23 | Object.assign(this, {token, displayName, avatarUrl}); 24 | } 25 | 26 | async sendMessage(message) { 27 | await axios.post(`https://webhooks.t2bot.io/api/v1/matrix/hook/${this.token}`, { 28 | text: message, 29 | format: 'plain', 30 | displayName: this.displayName, 31 | avatarUrl: this.avatarUrl 32 | }); 33 | } 34 | } 35 | 36 | async function start() { 37 | const client = new Client({ 38 | token: process.env.WEBHOOK_TOKEN, 39 | displayName: 'example-bot', 40 | avatarUrl: 'https://robohash.org/example-bot' 41 | }); 42 | await client.sendMessage('[matrix] rocks!'); 43 | } 44 | 45 | start().catch(err => { console.error(err); }); -------------------------------------------------------------------------------- /matrix-incoming-webhook/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "axios": { 6 | "version": "0.17.1", 7 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", 8 | "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", 9 | "requires": { 10 | "follow-redirects": "1.2.6", 11 | "is-buffer": "1.1.6" 12 | } 13 | }, 14 | "debug": { 15 | "version": "3.1.0", 16 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 17 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 18 | "requires": { 19 | "ms": "2.0.0" 20 | } 21 | }, 22 | "follow-redirects": { 23 | "version": "1.2.6", 24 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.6.tgz", 25 | "integrity": "sha512-FrMqZ/FONtHnbqO651UPpfRUVukIEwJhXMfdr/JWAmrDbeYBu773b1J6gdWDyRIj4hvvzQEHoEOTrdR8o6KLYA==", 26 | "requires": { 27 | "debug": "3.1.0" 28 | } 29 | }, 30 | "is-buffer": { 31 | "version": "1.1.6", 32 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 33 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 34 | }, 35 | "ms": { 36 | "version": "2.0.0", 37 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 38 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /matrix-incoming-webhook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "matrix-incoming-webhook", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "axios": "^0.17.1" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC" 16 | } 17 | -------------------------------------------------------------------------------- /openwhisk/README.md: -------------------------------------------------------------------------------- 1 | # Openwhisk 2 | 3 | ## Setup 4 | 5 | [Vagrant instructions](https://github.com/apache/incubator-openwhisk/tree/master/tools/vagrant) 6 | 7 | ``` bash 8 | git clone --depth=1 https://github.com/apache/incubator-openwhisk.git openwhisk 9 | cd openwhisk/tools/vagrant 10 | ``` 11 | 12 | Then bring vagrant up (this takes a long time): 13 | 14 | ``` bash 15 | vagrant up 16 | ``` 17 | 18 | Once it's up, ssh into the box: 19 | 20 | ``` bash 21 | vagrant ssh 22 | ``` 23 | 24 | ## Hello World 25 | 26 | ``` bash 27 | vi helloworld.js 28 | ``` 29 | 30 | ``` js 31 | function main() { 32 | message = "Hello World" 33 | return {message} 34 | } 35 | ``` 36 | 37 | ``` bash 38 | wsk action create helloworld helloworld.js 39 | wsk action invoke --blocking helloworld 40 | ``` 41 | 42 | This will output something like: 43 | 44 | ``` bash 45 | { 46 | "activationId": "b9a4fd3253ad43fca4fd3253ad23fc80", 47 | "annotations": [ 48 | { 49 | "key": "path", 50 | "value": "guest/helloworld" 51 | }, 52 | { 53 | "key": "waitTime", 54 | "value": 70 55 | }, 56 | { 57 | "key": "kind", 58 | "value": "nodejs:6" 59 | }, 60 | { 61 | "key": "limits", 62 | "value": { 63 | "logs": 10, 64 | "memory": 256, 65 | "timeout": 60000 66 | } 67 | }, 68 | { 69 | "key": "initTime", 70 | "value": 73 71 | } 72 | ], 73 | "duration": 140, 74 | "end": 1515476878314, 75 | "logs": [], 76 | "name": "helloworld", 77 | "namespace": "guest", 78 | "publish": false, 79 | "response": { 80 | "result": { 81 | "message": "Hello World" 82 | }, 83 | "status": "success", 84 | "success": true 85 | }, 86 | "start": 1515476878174, 87 | "subject": "guest", 88 | "version": "0.0.2" 89 | } 90 | ``` 91 | 92 | To run it non-blocking and get the result: 93 | 94 | ``` bash 95 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action invoke helloworld 96 | ok: invoked /guest/helloworld with id 76a052d557954d4ca052d557954d4c36 97 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk activation result 76a052d557954d4ca052d557954d4c36 98 | { 99 | "message": "Hello World" 100 | } 101 | ``` 102 | 103 | Modifying it to take a parameter: 104 | 105 | ``` bash 106 | vi helloworld.js 107 | ``` 108 | 109 | ``` js 110 | function main({name}) { 111 | message = `Hello ${name}` 112 | return {message} 113 | } 114 | ``` 115 | 116 | ``` bash 117 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action update hellworld helloworld.js 118 | ok: updated action hellworld 119 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action update helloworld helloworld.js 120 | ok: updated action helloworld 121 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action invoke helloworld 122 | ok: invoked /guest/helloworld with id cc22b01725024e4ea2b01725021e4ea8 123 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk activation result cc22b01725024e4ea2b01725021e4ea8 124 | { 125 | "message": "Hello undefined" 126 | } 127 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action invoke helloworld --param name Jack 128 | ok: invoked /guest/helloworld with id 20e7121db3f54301a7121db3f5c30198 129 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk activation result 20e7121db3f54301a7121db3f5c30198 130 | { 131 | "message": "Hello Jack" 132 | } 133 | ``` 134 | 135 | Setting a default param: 136 | 137 | ``` bash 138 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action update helloworld --param name World 139 | ok: updated action helloworld 140 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk action invoke helloworld 141 | ok: invoked /guest/helloworld with id 355a83ccb850471b9a83ccb850671b18 142 | vagrant@vagrant-ubuntu-trusty-64:~$ wsk activation result 355a83ccb850471b9a83ccb850671b18 143 | { 144 | "message": "Hello World" 145 | } 146 | ``` -------------------------------------------------------------------------------- /rocketchat-webhook/README.md: -------------------------------------------------------------------------------- 1 | [RocketChat webhook][url] 2 | 3 | 1. Run `yarn init -y` and `yarn add micro` 4 | 2. Log into Rocket.Chat, go to the Administration Panel, and choose 5 | Integrations 6 | 3. Select "New Integration", and then "Outgoing Webhook" 7 | 4. Select "Message Sent" for the Event Trigger 8 | 5. Set "Enabled" to true and give it a name (like "testing123") 9 | 6. Enter a channel name ("#general") and a trigger word (like "testing123") 10 | 7. Enter a URL, which is the server you'll deploy to and a path: 11 | Example: `https://rocketchat-testing123.now.sh/` 12 | 8. Several fields down is the Token. It will contain an automatically 13 | generated one. Copy that and set it as the `WEBHOOK_TOKEN` environment 14 | variable: 15 | ``` bash 16 | export WEBHOOK_TOKEN=oWgqqKpcFC6vSzkCMipBAETF 17 | ``` 18 | 9. Click `Save Changes`. Deploy the app or expose it via ngrok and run it: 19 | ``` bash 20 | # https://zeit.co/now deployment 21 | now -e WEBHOOK_TOKEN=$WEBHOOK_TOKEN 22 | export DEPLOYMENT_URL=$(pbpaste) 23 | now alias $DEPLOYMENT_URL rocketchat-testing123.now.sh 24 | 25 | # for ngrok, open a new console tab and run ngrok 26 | # When ngrok provides the URL, copy and paste the URL and update the 27 | # webhook in the RocketChat admin 28 | ngrok http 3000 29 | 30 | # And the original tab run the micro server 31 | yarn start 32 | ``` 33 | 10. Go to the channel and send a message starting with the trigger text. 34 | 35 | [url]: https://github.com/resources/snippets/tree/master/rocketchat-webhook 36 | 37 | ``` javascript 38 | const {json, send} = require('micro') 39 | 40 | if (! process.env.WEBHOOK_TOKEN) { 41 | throw new Error('The WEBHOOK_TOKEN environment variable must be set.') 42 | } 43 | 44 | module.exports = async (req, res) => { 45 | const data = await json(req) 46 | if (data.token !== process.env.WEBHOOK_TOKEN) { 47 | return send(res, 401, { error: 'Invalid Token' }) 48 | } 49 | const message = data.text.replace(data.trigger_word, '').trimLeft() 50 | return { text: `You said: ${message}` } 51 | } 52 | ``` -------------------------------------------------------------------------------- /rocketchat-webhook/index.js: -------------------------------------------------------------------------------- 1 | // [RocketChat webhook][url] 2 | // 3 | // 1. Run `yarn init -y` and `yarn add micro` 4 | // 2. Log into Rocket.Chat, go to the Administration Panel, and choose 5 | // Integrations 6 | // 3. Select "New Integration", and then "Outgoing Webhook" 7 | // 4. Select "Message Sent" for the Event Trigger 8 | // 5. Set "Enabled" to true and give it a name (like "testing123") 9 | // 6. Enter a channel name ("#general") and a trigger word (like "testing123") 10 | // 7. Enter a URL, which is the server you'll deploy to and a path: 11 | // Example: `https://rocketchat-testing123.now.sh/` 12 | // 8. Several fields down is the Token. It will contain an automatically 13 | // generated one. Copy that and set it as the `WEBHOOK_TOKEN` environment 14 | // variable: 15 | // ``` bash 16 | // export WEBHOOK_TOKEN=oWgqqKpcFC6vSzkCMipBAETF 17 | // ``` 18 | // 9. Click `Save Changes`. Deploy the app or expose it via ngrok and run it: 19 | // ``` bash 20 | // # https://zeit.co/now deployment 21 | // now -e WEBHOOK_TOKEN=$WEBHOOK_TOKEN 22 | // export DEPLOYMENT_URL=$(pbpaste) 23 | // now alias $DEPLOYMENT_URL rocketchat-testing123.now.sh 24 | // 25 | // # for ngrok, open a new console tab and run ngrok 26 | // # When ngrok provides the URL, copy and paste the URL and update the 27 | // # webhook in the RocketChat admin 28 | // ngrok http 3000 29 | // 30 | // # And the original tab run the micro server 31 | // yarn start 32 | // ``` 33 | // 10. Go to the channel and send a message starting with the trigger text. 34 | // 35 | // [url]: https://github.com/resources/snippets/tree/master/rocketchat-webhook 36 | const {json, send} = require('micro') 37 | 38 | if (! process.env.WEBHOOK_TOKEN) { 39 | throw new Error('The WEBHOOK_TOKEN environment variable must be set.') 40 | } 41 | 42 | module.exports = async (req, res) => { 43 | const data = await json(req) 44 | if (data.token !== process.env.WEBHOOK_TOKEN) { 45 | return send(res, 401, { error: 'Invalid Token' }) 46 | } 47 | const message = data.text.replace(data.trigger_word, '').trimLeft() 48 | return { text: `You said: ${message}` } 49 | } -------------------------------------------------------------------------------- /rocketchat-webhook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rocketchat-webhook", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "micro": "^9.0.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /rocketchat-webhook/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | bytes@3.0.0: 6 | version "3.0.0" 7 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 8 | 9 | content-type@1.0.4: 10 | version "1.0.4" 11 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 12 | 13 | depd@1.1.1: 14 | version "1.1.1" 15 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 16 | 17 | http-errors@1.6.2: 18 | version "1.6.2" 19 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 20 | dependencies: 21 | depd "1.1.1" 22 | inherits "2.0.3" 23 | setprototypeof "1.0.3" 24 | statuses ">= 1.3.1 < 2" 25 | 26 | iconv-lite@0.4.19: 27 | version "0.4.19" 28 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" 29 | 30 | inherits@2.0.3: 31 | version "2.0.3" 32 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 33 | 34 | is-stream@1.1.0: 35 | version "1.1.0" 36 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 37 | 38 | micro@^9.0.2: 39 | version "9.0.2" 40 | resolved "https://registry.yarnpkg.com/micro/-/micro-9.0.2.tgz#fa51f12d09fa29bdf9767d6eac43414ae3fb6068" 41 | dependencies: 42 | content-type "1.0.4" 43 | is-stream "1.1.0" 44 | mri "1.1.0" 45 | raw-body "2.3.2" 46 | 47 | mri@1.1.0: 48 | version "1.1.0" 49 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.0.tgz#5c0a3f29c8ccffbbb1ec941dcec09d71fa32f36a" 50 | 51 | raw-body@2.3.2: 52 | version "2.3.2" 53 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" 54 | dependencies: 55 | bytes "3.0.0" 56 | http-errors "1.6.2" 57 | iconv-lite "0.4.19" 58 | unpipe "1.0.0" 59 | 60 | setprototypeof@1.0.3: 61 | version "1.0.3" 62 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 63 | 64 | "statuses@>= 1.3.1 < 2": 65 | version "1.4.0" 66 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" 67 | 68 | unpipe@1.0.0: 69 | version "1.0.0" 70 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 71 | --------------------------------------------------------------------------------