Skip to content

Commit

Permalink
Merge branch 'release/0.1.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
shawn-mcginty committed Aug 31, 2020
2 parents 07d49f9 + 2037a5d commit 453ccba
Show file tree
Hide file tree
Showing 27 changed files with 604 additions and 135 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Simple, fast, minimalist web framework for [OCaml](https://ocaml.org)/[ReasonML]
[https://naboris.dev](https://naboris.dev)

[![Build Status](https://travis-ci.com/shawn-mcginty/naboris.svg?branch=master)](https://travis-ci.com/shawn-mcginty/naboris)
[![opam version 0.1.2](https://img.shields.io/static/v1?label=opam&message=0.1.2&color=E7C162)](https://opam.ocaml.org/packages/naboris/)
[![opam version 0.1.3](https://img.shields.io/static/v1?label=opam&message=0.1.3&color=E7C162)](https://opam.ocaml.org/packages/naboris/)

```reason
// ReasonML
Expand Down Expand Up @@ -74,7 +74,7 @@ opam install naboris

#### esy
```json
"@opam/naboris": "^0.1.2"
"@opam/naboris": "^0.1.3"
```

#### dune
Expand Down Expand Up @@ -116,6 +116,7 @@ npm run test

| From | To | Breaking Change |
| --- | --- | --- |
| `0.1.2` | `0.1.3` | `secret` argument added to all session configuration APIs. |
| `0.1.0` | `0.1.1` | `ServerConfig.setSessionGetter` changed to `ServerConfig.setSessionConfig` which also allows `~maxAge` and `~sidKey` to be passed in optionally. |
| `0.1.0` | `0.1.1` | All `RequestHandler.t` and `Middleware.t` now return `Lwt.t(Res.t)` instead of `Lwt.t(unit)` |
| `0.1.0` | `0.1.1` | `Res.reportError` now taxes `exn` as the first argument to match more closely the rest of the `Res` API. |
2 changes: 1 addition & 1 deletion docs-src/content/docs/guides/security-best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ server {
```

#### <a name="session-configuration" href="#session-configuration">#</a> Session Configuration
If your server makes use of sessions it is important to change the default session id key. This makes many automated attacks much more difficult. [`ServerConfig.setSessionConfig`](http://localhost:3999/odocs/naboris/Naboris/ServerConfig/index.html#val-setSessionConfig) takes an optional parameter `~sidKey` making it very easy to change the default session id key.
If your server makes use of sessions it is important to change the default session id key. This makes many automated attacks much more difficult. [`ServerConfig.setSessionConfig`](http://localhost:3999/odocs/naboris/Naboris/ServerConfig/index.html#val-setSessionConfig) takes optional parameter `~sidKey` making it very easy to change the default session id key. More importantly the optional parameter `~secret` sets the secret used when signing session id cookies.


#### <a name="follow-http-best-practices" href="#follow-http-best-practices">#</a> Follow HTTP Best Practices
Expand Down
8 changes: 4 additions & 4 deletions docs-src/content/docs/guides/sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ Many `Naboris` types take the parameter `'sessionData` this represents a custom

#### <a name="session-config" href="#session-config">#</a> Session Config
[`ServerConfig.setSessionConfig`](/odocs/naboris/Naboris/ServerConfig/index.html#val-setSessionConfig) will return a new server configuration with the desired
session configuration. This call consists of one required argument `mapSession` and two
optional arguments `~maxAge` and `~sidKey`.
session configuration. This call consists of one required argument `mapSession` and three optional arguments `~maxAge`, `~sidKey`, and `~secret`.

```reason
let setSessionConfig: (~maxAge: int=?, ~sidKey: string=?, option(string) => Lwt.t(option(Session.t('sessionData))), ServerConfig.t('sessionData)) => ServerConfig.t('sessionData);
let setSessionConfig: (~maxAge: int=?, ~sidKey: string=?, ~secret: string=?, option(string) => Lwt.t(option(Session.t('sessionData))), ServerConfig.t('sessionData)) => ServerConfig.t('sessionData);
```
```ocaml
val setSessionConfig: ?maxAge: int -> ?sidKey: string -> string option -> 'sessionData Session.t option Lwt.t -> 'sessionData ServerConfig.t -> 'sessionData ServerConfig.t
val setSessionConfig: ?maxAge: int -> ?sidKey: string -> ?secret: string -> string option -> 'sessionData Session.t option Lwt.t -> 'sessionData ServerConfig.t -> 'sessionData ServerConfig.t
```

* `sidKey` - `string` (optional) - The key used to store the session id in browser cookies. Defaults to `"nab.sid"`.
* `maxAge` - `int` (optional) - The max age of session cookies in seconds. Defaults to `2592000` (30 days).
* `secret` - `string` (optional) - A secret string used to sign session id cookies.
* `mapSession` - covered in the section below.

#### <a name="session-mapping" href="#session-mapping">#</a> Session Mapping
Expand Down
5 changes: 3 additions & 2 deletions docs-src/content/docs/quick-start/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ GitHub. These projects use [esy](https://esy.sh) to sandbox opam and build. This

OCaml:
```bash
$ git clone git@github.com:shawn-mcginty/naboris-ocaml-scaffold.git
$ git clone git@github.com:shawn-mcginty/naboris-ml-scaffold.git
$ npm run install
$ npm run build
$ npm run start
Expand Down Expand Up @@ -100,4 +100,5 @@ If you use **esy** for sandboxing you'll have to use a special resolution:
}
```

_Notes about esy custom resolution: This is pegged to a specific commit. At the time of this writing the commit listed above worked great. You may need to check the [GitHub repo](https://github.com/esy-packages/libev) and switch to a fresher commit._
_Notes about esy custom resolution: This is pegged to a specific commit. At the time of this writing the commit listed above worked great. You may need to check the [GitHub repo](https://github.com/esy-packages/libev) and switch to a fresher commit._

4 changes: 2 additions & 2 deletions libev.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "naboris",
"version": "0.1.2",
"version": "0.1.3",
"description": "Simple http server built on httpaf and lwt.",
"esy": {
"build": [
Expand Down Expand Up @@ -52,4 +52,4 @@
"resolutions": {
"@opam/conf-libev": "esy-packages/libev:package.json#0b5eb66"
}
}
}
3 changes: 2 additions & 1 deletion naboris.opam
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
opam-version: "2.0"
name: "naboris"
version: "0.1.2"
version: "0.1.3"
synopsis: "Simple http server"
description: "Simple http server built on httpaf and lwt"
maintainer: "Shawn McGinty <loltempast@gmail.com>"
Expand All @@ -15,6 +15,7 @@ build: [
]
depends: [
"ocaml" {>= "4.07"}
"base64" {>= "3.4.0"}
"dune" {>= "1.6"}
"reason" {>= "3.4.0"}
"httpaf" {>= "0.6.0"}
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "naboris",
"version": "0.1.2",
"version": "0.1.3",
"description": "Simple http server built on httpaf and lwt.",
"esy": {
"build": [
Expand Down Expand Up @@ -35,11 +35,14 @@
},
"homepage": "https://github.com/shawn-mcginty/naboris#readme",
"dependencies": {
"@opam/base64": ">=3.4.0",
"@opam/dune": "*",
"@opam/digestif": ">=0.8.0",
"@opam/reason": ">=3.4.0",
"@opam/httpaf": ">=0.6.0",
"@opam/httpaf-lwt-unix": ">=0.6.0",
"@opam/lwt": ">=5.1.1",
"@opam/lwt_ppx": ">=2.0.1",
"@opam/uri": ">=2.2.0"
},
"devDependencies": {
Expand Down
20 changes: 8 additions & 12 deletions src/Naboris.re
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ module Cookie = Cookie;
module ServerConfig = ServerConfig;
module SessionConfig = SessionConfig;
module ErrorHandler = ErrorHandler;

open Lwt.Infix;
module DateUtils = DateUtils;
module Etag = Etag;

let listen =
(
Expand All @@ -26,18 +26,14 @@ let listen =
let listenAddress = Unix.(ADDR_INET(inetAddr, port));
let connectionHandler = Server.buildConnectionHandler(serverConfig);

Lwt.async(() =>
Lwt_io.establish_server_with_client_socket(
Lwt.async(() => {
let%lwt _server = Lwt_io.establish_server_with_client_socket(
listenAddress,
connectionHandler,
)
>>= (
_server => {
ServerConfig.onListen(serverConfig, ());
Lwt.return_unit;
}
)
);
);
ServerConfig.onListen(serverConfig, ());
Lwt.return_unit;
});

Lwt.wait();
};
Expand Down
10 changes: 9 additions & 1 deletion src/Naboris.rei
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ module Middleware = Middleware;
*/
module RequestHandler = RequestHandler;

/**
Module with some utility functions for dates for HTTP headers.
*/
module DateUtils = DateUtils;

/**
[Map] type for working with queries from routed requests.
*/
Expand All @@ -76,4 +81,7 @@ module SessionManager = SessionManager;
module Router = Router;

/** {b Less commonly used.} */
module SessionConfig = SessionConfig;
module SessionConfig = SessionConfig;

/** {b Less commonly used.} */
module Etag = Etag;
19 changes: 16 additions & 3 deletions src/Req.re
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ type t('sessionData) = {
session: option(Session.t('sessionData)),
sidKey: string,
maxAge: int,
secret: string,
staticCacheControl: option(string),
staticLastModified: bool,
responseEtag: option(Etag.strength),
};

let reqd = req => req.requestDescriptor;
Expand All @@ -28,10 +32,11 @@ let getBody = ({requestDescriptor, _}) => {
Lwt_stream.fold((a, b) => a ++ b, bodyStream, "");
};

let fromReqd = (reqd, sessionConfig) => {
let fromReqd = (reqd, sessionConfig, staticCacheControl, staticLastModified, responseEtag) => {
let sidKey = SessionConfig.sidKey(sessionConfig);
let maxAge = SessionConfig.maxAge(sessionConfig);
let defaultReq = {requestDescriptor: reqd, session: None, sidKey, maxAge};
let secret = SessionConfig.secret(sessionConfig);
let defaultReq = {requestDescriptor: reqd, session: None, sidKey, maxAge, secret, staticCacheControl, staticLastModified, responseEtag};
defaultReq;
};

Expand All @@ -48,4 +53,12 @@ let setSessionData = (maybeSession, req) => {

let sidKey = req => req.sidKey;

let maxAge = req => req.maxAge;
let maxAge = req => req.maxAge;

let secret = req => req.secret;

let staticCacheControl = req => req.staticCacheControl;

let staticLastModified = req => req.staticLastModified;

let responseEtag = req => req.responseEtag;
24 changes: 22 additions & 2 deletions src/Req.rei
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let setSessionData: (option(Session.t('sessionData)), t('sessionData)) => t('ses
{b Intended for internal use.}
Creates default req record.
*/
let fromReqd: (Httpaf.Reqd.t, option(SessionConfig.t('sessionData))) => t('sessionData);
let fromReqd: (Httpaf.Reqd.t, option(SessionConfig.t('sessionData)), option(string), bool, option(Etag.strength)) => t('sessionData);

/**
Get key for session id cookie
Expand All @@ -43,4 +43,24 @@ let sidKey: t('sessionData) => string;
/**
Get max age for session id cookies (in seconds)
*/
let maxAge: t('sessionData) => int;
let maxAge: t('sessionData) => int;

/**
Get secret used to sign session id cookies.
*/
let secret: t('sessionData) => string;

/**
Get [Cache-control] header value for static requests based on [ServerConfig.t].
*/
let staticCacheControl: t('sessionData) => option(string);

/**
Get [bool] value where true signals the server to set [Last-modified] headers for static requests.
*/
let staticLastModified: t('sessionData) => bool;

/**
Get [option([`Strong | `Weak])] which is set by [ServerConfig.t].
*/
let responseEtag: t('sessionDate) => option(Etag.strength);
Loading

0 comments on commit 453ccba

Please sign in to comment.