Skip to content
[fork] Signed And Unsigned Cookies Based On Keygrip Written In ES6 And Optimised With JavaScript Compiler.
JavaScript
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.documentary/section-breaks
.vscode
compile
documentary
example
src
test
types
wiki
.alamoderc.json
.eslintignore
.eslintrc
.gitignore
CHANGELOG.md
LICENSE
README
README.md
package.json
yarn.lock

README.md

@goa/cookies

npm version

@goa/cookies is a fork of 🗝 Signed And Unsigned Cookies Based On Keygrip Written In ES6, Annotated With Externs And Optimised With JavaScript Compiler.

The original module was edited with annotations and other changes required for it to be used in @goa/koa: Koa web server compiled with Closure Compiler using Depack into a single file library (with 1 dependency such as mime-db).

Read more about the compilation.

All dependencies are specified as dev dependencies because they are flattened into a single JS file by the compiler, unless the special require(/* depack ok */ 'modulejs') was called, which will require the package at run-time, for instance this is how mime-db is required by Goa.

The package specifies the following entry points:

  • commonjs/main: the require entry optimised with compiler. Used for individual consumption of the package's API.
    compile
    ├── cookies.js
    ├── cookies.js.map
    └── index.js
    
  • es6/module: the source code that can be used in compilation of other packages, e.g., @goa/goa.
    src
    ├── Cookie.js
    ├── Keygrip.js
    ├── depack.js
    ├── index.js
    └── keygrip-lib
        ├── ctc.js
        └── sign.js
    

The tests were rewritten using context testing. The Http Context, in particular the Cookie Tester was used to assert on presence of entries, and their attributes.

Show the tests.
'with "secure: true" constructor option': {
  async 'sets secure attribute on unencrypted connection'(
    { start, c }) {
    const opts = { secure: true } // constructor options
    await start(c((req, res, cookies) => {
      cookies.set('foo', 'bar', { secure: true })
      res.end()
    }, opts))
      .get('/')
      .assert(200)
      .attribute('foo', 'Secure')
  },
},
'with req.protocol === "https"': {
  async 'sets secure attribute on unencrypted connection'(
    { start, c }) {
    await start(c((req, res, cookies) => {
      req.protocol = 'https'
      cookies.set('foo', 'bar', { secure: true })
      res.end()
    }))
      .get('/')
      .assert(200)
      .attribute('foo', 'Secure')
  },
},
yarn add @goa/cookies

Table Of Contents

API

The package is available by importing its default function:

import Cookies, { Keygrip, express, connect } from '@goa/cookies'

The deprecated secureProxy, maxage attributes of a cookie have been removed. The constructor only accepts the { keys: Array<string>|Keygrip } option, without being able to pass keys as an array, or Keygrip as an object. Please make sure no middleware is using these options.

class Cookies

Cookies is a Node.JS module for getting and setting HTTP(S) cookies. Cookies can be signed to prevent tampering, using Keygrip. It can be used with the built-in Node.JS HTTP library, or as Connect/Express middleware.

constructor(
  request: IncomingMessage,
  response: ServerResponse,
  options: CookiesOptions,
): Cookies

This creates a cookie jar corresponding to the current request and response, additionally passing an object options.

A Keygrip object or an array of keys can optionally be passed as options.keys to enable cryptographic signing based on SHA1 HMAC, using rotated credentials.

A Boolean can optionally be passed as options.secure to explicitly specify if the connection is secure, rather than this module examining request.

Note that since this only saves parameters without any other processing, it is very lightweight. Cookies are only parsed on demand when they are accessed.

import('http').IncomingMessage http.IncomingMessage: The first argument to the "request" event.

import('http').ServerResponse http.ServerResponse: The second parameter to the "request" event.

CookiesOptions: Options for the constructor.

Name Type Description
keys !(Array<string> | Keygrip) The array of keys, or the Keygrip object.
secure boolean Explicitly specifies if the connection is secure, rather than this module examining request.
Node.JS HTTP Server Example
import Cookies from '@goa/cookies'
import aqt from '@rqt/aqt'
import { createServer } from 'http'

// Optionally define keys to sign cookie values
// to prevent client tampering
const keys = ['keyboard cat']

const server = createServer((req, res) => {
  // Create a cookies object
  const cookies = new Cookies(req, res, { keys: keys })

  // Get a cookie
  const lastVisit = cookies.get('LastVisit', { signed: true })

  // Set the cookie to a value
  cookies.set('LastVisit', new Date().toISOString(), { signed: true })

  if (!lastVisit) {
    res.setHeader('Content-Type', 'text/plain')
    res.end('Welcome, first time visitor!')
  } else {
    res.setHeader('Content-Type', 'text/plain')
    res.end('Welcome back! Nothing much changed since your last visit at ' + lastVisit + '.')
  }
})

server.listen(async () => {
  const url = `http://localhost:${server.address().port}`
  console.log(url)
  let { body, headers } = await aqt(url)
  console.log(body, headers['set-cookie'].join('\n'))
  ;({ body } = await aqt(url, {
    headers: { Cookie: headers['set-cookie'] },
  }))
  console.log(body)
  server.close()
})
The output
http://localhost:56593
Welcome, first time visitor! LastVisit=2019-07-25T22:53:04.827Z; path=/; httponly
LastVisit.sig=zvL2h3aYesSL-t8sk35FJgrsxg0; path=/; httponly
Welcome back! Nothing much changed since your last visit at 2019-07-25T22:53:04.827Z.

The overview of the Cookies interface is found in wiki.

set(
  name: string,
  value=: ?,
  opts=: CookieSetOptions&CookieAttributes,
): void

This sets the given cookie in the response and returns the current context to allow chaining. If the value is omitted, an outbound header with an expired date is used to delete the cookie.

CookieSetOptions extends CookieAttributes: How the cookie will be set.

Name Type Description Default
signed boolean Indicating whether the cookie is to be signed. If this is true, another cookie of the same name with the .sig suffix appended will also be sent, with a 27-byte url-safe base64 SHA1 value representing the hash of cookie-name=cookie-value against the first Keygrip key. This signature key is used to detect tampering the next time a cookie is received. false

The attributes accepted by the cookie instance are listed in wiki.

get(
  name: string,
  opts=: CookieSetOptions,
): string

Returns the cookie with the given name if it was previously set. The signed option might be passed to specify if a signed cookie is being accessed.

Wiki

Wiki contains the following pages with additional information about the package.

🍪 Cookie Attributes

Cookies Attributes: domain, expires, httpOnly, maxAge, overwrite, path, sameSite, secure

🚄 Express And Connect Middleware Constructor

Cookies can be used via express and connect easily by calling the middleware constructor functions to get middleware that can be installed on the app.

⚜️ Keygrip

The Keygrip can be passed in the keys property of the constructor. By default, the new instance of Keygrip will be created when an array of keys is passed, but custom implementations of Keygrip which override the sign and verify functions can be passed to cookies.

🔗 View Compiler Externs

The externs are required to compile the package yet keep the options' properties in tact, i.e. without renaming the properties. The API is preserved for 2nd level compilation in other packages, such as Goa, and is tested on the 1st level compilation of the package itself.

Copyright & Status

Original source, documentation and testing by Jed Schmidt & Douglas Christopher Wilson.

Forked Off cookies 0.7.3 Apr 24

Current: npm version


Art Deco © Art Deco for Idio 2019 Idio Tech Nation Visa Tech Nation Visa Sucks

You can’t perform that action at this time.