Skip to content

Commit

Permalink
Added support for Unix Timestamp (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ununnilium authored and denji committed Mar 6, 2019
1 parent b0072cf commit c7240fc
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 41 deletions.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Usage:

Message to be hashed is defined by `secure_link_hmac_message`, `secret_key` is given by `secure_link_hmac_secret`, and hashing algorithm H is defined by `secure_link_hmac_algorithm`.

For improved security the timestamp in ISO 8601 format should be appended to the message to be hashed.
For improved security the timestamp in ISO 8601 the format `2017-12-08T07:54:59+00:00` (one possibility according to ISO 8601) or as `Unix Timestamp` should be appended to the message to be hashed.

It is possible to create links with limited lifetime. This is defined by an optional parameter. If the expiration period is zero or it is not specified, a link has the unlimited lifetime.

Expand Down Expand Up @@ -111,6 +111,21 @@ $host = $_SERVER['HTTP_HOST'];
$loc = "https://{$host}/files/top_secret.pdf?st={$hashmac}&ts={$timestamp}&e={$expire}";
```

Using Unix timestamp in Node.js

```javascript
const crypto = require("crypto");
const secret = 'my_very_secret_key';
const expire = 60;
const unixTimestamp = Math.round(Date.now() / 1000.);
const stringToSign = `/files/top_secret.pdf${unixTimestamp}${expire}`;
const hashmac = crypto.createHmac('sha256', secret).update(stringToSign).digest('base64')
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
const loc = `https://host/files/top_secret.pdf?st=${hashmac}&ts=${unixTimestamp}&e=${expire}`;
```

It is also possible to use this module with a Nginx acting as proxy server.

The string to be signed is defined in `secure_link_hmac_message`, the `secure_link_hmac_token` variable contains then a secure token to be passed to backend server.
Expand Down
89 changes: 49 additions & 40 deletions ngx_http_hmac_secure_link_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ ngx_http_secure_link_variable(ngx_http_request_t *r,
u_char hash_buf[EVP_MAX_MD_SIZE], hmac_buf[EVP_MAX_MD_SIZE];
u_int hmac_len;
time_t timestamp, expires, gmtoff;
unsigned long long conv_timestamp;
int year, month, mday, hour, min, sec, gmtoff_hour, gmtoff_min;
char gmtoff_sign;

Expand Down Expand Up @@ -156,50 +157,58 @@ ngx_http_secure_link_variable(ngx_http_request_t *r,
"secure link timestamp: \"%*s\"",
sizeof("1970-09-28T12:00:00+06:00")-1, p);

/* Parse timestamp in ISO8601 format */
if (sscanf((char *)p, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i",
(ngx_tm_year_t *) &year, (ngx_tm_mon_t *) &month,
(ngx_tm_mday_t *) &mday, (ngx_tm_hour_t *) &hour,
(ngx_tm_min_t *) &min, (ngx_tm_sec_t *) &sec,
&gmtoff_sign, &gmtoff_hour, &gmtoff_min) < 9) {
goto not_found;
}
/* Try if p is UNIX timestamp*/
if (sscanf((char *)p, "%llu", &conv_timestamp) == 1) {
timestamp = (time_t)conv_timestamp;

/* Put February last because it has leap day */
month -= 2;
if (month <= 0) {
month += 12;
year -= 1;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secure link timestamp: \"%T\"", timestamp);
} else {
/* Parse timestamp in ISO8601 format */
if (sscanf((char *)p, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i",
(ngx_tm_year_t *) &year, (ngx_tm_mon_t *) &month,
(ngx_tm_mday_t *) &mday, (ngx_tm_hour_t *) &hour,
(ngx_tm_min_t *) &min, (ngx_tm_sec_t *) &sec,
&gmtoff_sign, &gmtoff_hour, &gmtoff_min) < 9) {
goto not_found;
}

/* Gauss' formula for Gregorian days since March 1, 1 BC */
/* Taken from ngx_http_parse_time.c */
timestamp = (time_t) (
/* days in years including leap years since March 1, 1 BC */
365 * year + year / 4 - year / 100 + year / 400
/* days before the month */
+ 367 * month / 12 - 30
/* days before the day */
+ mday - 1
/*
* 719527 days were between March 1, 1 BC and March 1, 1970,
* 31 and 28 days were in January and February 1970
*/
- 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;

/* Determine the time offset with respect to GMT */
gmtoff = 3600 * gmtoff_hour + 60 * gmtoff_min;

if (gmtoff_sign == '+') {
timestamp -= gmtoff;
}
/* Put February last because it has leap day */
month -= 2;
if (month <= 0) {
month += 12;
year -= 1;
}

if (gmtoff_sign == '-') {
timestamp += gmtoff;
}
/* Gauss' formula for Gregorian days since March 1, 1 BC */
/* Taken from ngx_http_parse_time.c */
timestamp = (time_t) (
/* days in years including leap years since March 1, 1 BC */
365 * year + year / 4 - year / 100 + year / 400
/* days before the month */
+ 367 * month / 12 - 30
/* days before the day */
+ mday - 1
/*
* 719527 days were between March 1, 1 BC and March 1, 1970,
* 31 and 28 days were in January and February 1970
*/
- 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;

/* Determine the time offset with respect to GMT */
gmtoff = 3600 * gmtoff_hour + 60 * gmtoff_min;

if (gmtoff_sign == '+') {
timestamp -= gmtoff;
}

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secure link timestamp: \"%T\"", timestamp);
if (gmtoff_sign == '-') {
timestamp += gmtoff;
}

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secure link timestamp: \"%T\"", timestamp);
}

if (timestamp <= 0) {
goto not_found;
Expand Down

0 comments on commit c7240fc

Please sign in to comment.