Documented the auth system.

main
Zed A. Shaw 2 years ago
parent 253d5b5b9f
commit 233aae8662
  1. 81
      lib/auth.js

@ -1,3 +1,16 @@
/*
Implements everything needed for a [Passport.js](https://www.passportjs.org) middleware.
It supports either a Redis store or a MemoryStore. The MemoryStore can be used in development
if you can't or won't run Redis while you work. Ultimately you should be using the Redis
store even in development as it keeps you logged in while you work which is easier.
The type of store is configured in the `secrets/config.json` file (which is loaded into `lib/config.js`) using the `session_store` option. See `configure_sessions` for more information on this
configuration option.
The most important part of this module is the `socket` function, which adds `Passport.js`
authentication to `socket.io` which is something missing from `Passport.js`. Look at that
if you wondered how to do that.
*/
import cookie from 'cookie'; import cookie from 'cookie';
import { Strategy } from 'passport-local'; import { Strategy } from 'passport-local';
import passport from 'passport'; import passport from 'passport';
@ -43,6 +56,17 @@ passport.deserializeUser(async (id, cb) => {
} }
}); });
/*
Configures `Passport.js` to use either `RedisStore` or `MemoryStore`. If you want to
add a different store then modify this function. If the `config.json:session_store` is
`"redis"` you'll get the `RedisStore`. If it's set to `"memory"` then it will use the
`MemoryStore`.
___WARNING___: You don't really call this and instead use the `sessionStore` variable in
this module.
+ ___return___ (RedisStore|MemoryStore|undefined) -- The store to use or `undefined` on error.
*/
export const configure_sessions = () => { export const configure_sessions = () => {
if(session_store === "redis") { if(session_store === "redis") {
log.info("Using redis to store sessions."); log.info("Using redis to store sessions.");
@ -56,12 +80,46 @@ export const configure_sessions = () => {
} }
} }
/*
* The configured session store being used. Just use this instead of
* calling `configure_sessions` yourself.
*/
export const sessionStore = configure_sessions(); export const sessionStore = configure_sessions();
/*
The cookie secret configured in `secrets/config.json:auth`.
___FOOTGUN___: Don't expose this to the internet!
*/
export const cookie_secret = auth.cookie_secret; export const cookie_secret = auth.cookie_secret;
/*
The cookie _domain_ configured in `secrets/config.json:auth`. If this isn't
exactly the same as your domain then you'll not be able to log in. You can
run:
```shell
node bando.js api --cookies-suck
```
This will output cookie debugging information so you can figure out what's going on.
Incidentally, debugging the stupid cookies ends up a huge chunk of the code in `commands/api.js`
because, you guessed it, `--cookies-suck`.
*/
export const cookie_domain = auth.cookie_domain; export const cookie_domain = auth.cookie_domain;
assert(cookie_domain !== undefined, "secrets/config.json:auth.cookie_domain isn't set."); assert(cookie_domain !== undefined, "secrets/config.json:auth.cookie_domain isn't set.");
/*
This does the actual `Passport.js` login, but you wouldn't necessarily use this
directly unless you are making something custom. Instead, you "tag" handlers
in `api/` handlers with `.login = true` and then the `commands/api.js` will
automatically run this before running your handler. Look in `api/login.js` to see
how to use `post.login = true` to actually use this.
If you want to see how this is used, look for `auth.login` in `commands/api.js`.
+ ___return__ Function -- Returns a Express.js handler that does the `passport.authenticate`.
*/
export const login = () => { export const login = () => {
return (req, res, next) => { return (req, res, next) => {
passport.authenticate('local', (err, user, info) => { passport.authenticate('local', (err, user, info) => {
@ -89,6 +147,13 @@ export const login = () => {
} }
} }
/*
An Express.js handler that make authentication required. Just like with `login` it
is normally used by adding the `.authenticated = true` tag to your handlers. If you
do `get.authenticated = true` then that `get` will require a login before it runs.
The `commands/api.js` command is the one that uses this `require` function to add that
feature to your handlers in `api/`.
*/
export const required = () => { export const required = () => {
return (req, res, next) => { return (req, res, next) => {
const user = req.user; const user = req.user;
@ -101,7 +166,17 @@ export const required = () => {
} }
} }
/*
* This is added to any `socket/` handlers tagged with `.authenticated`. It does
* the same thing as `required` above but instead does all the fairly stupid things
* you need to authenticate a `socket.io` connection.
*
* It's main purpose is to authenticate, but _also_ to connect the `req.user` to the
* socket so you can access the user in your `socket/` handlers.
*
* + `socket Object` -- A socket.io socket to authenticate.
* + ___return___ `boolean` -- A `Promise` that performs the authentication then adds the `req.user` to the socket.
*/
export const socket = async (socket) => { export const socket = async (socket) => {
try { try {
if(!socket.handshake.headers.cookie) { if(!socket.handshake.headers.cookie) {
@ -157,7 +232,9 @@ export const socket = async (socket) => {
} }
} }
/*
Initializes your Express.js application with the `Passport.js` required handlers.
*/
export const init = (app) => { export const init = (app) => {
app.use(passport.initialize()); app.use(passport.initialize());
app.use(passport.session()); app.use(passport.session());

Loading…
Cancel
Save