Skip to content

Commit ec6529d

Browse files
committed
Adopt a portion of SRI for our implementation
* This was already implemented pre W3C recommendation in our form but normalizing to their syntax. * UI and DB remaining non-base64 encoded... semver limitation with extra characters that violate that spec. * Change caching mechanism... unfortunately traffic for a while will be increased while syncing with browsers. Also because spec doesn't use hex, which it probably should, the eTag header value will be bigger. Hashes, so far, are always "hex-able" by design of SHA but that could change in the future... who knows. * Base62 being dropped in favor of Base64 for cache mechanism. Should be okay with extra `+/` in base64 since that falls within ASCII limitations. * Any .user.js utilizing the .meta.json, or other language, will need to modify to check for the `sha512-` prefix and decode the value appropriately. * If .meta.json shows empty `hash` clear browser cache *(weird Fx issue perhaps)* * Bugfix on local copy of metadata script access... non-fatal atm just incorrect live copy referenced. Post OpenUserJS#1076 and applies to OpenUserJS#432 OpenUserJS#249 Ref(s): * https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag * https://developer.mozilla.org/docs/Web/Security/Subresource_Integrity * https://w3c.github.io/webappsec-subresource-integrity/ * https://www.srihash.org/
1 parent ab7379e commit ec6529d

File tree

5 files changed

+29
-23
lines changed

5 files changed

+29
-23
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ Repository | Reference | Recent Version
2424
[ansi-colors][ansi-colorsGHUrl] | [Documentation][ansi-colorsDOCUrl] | [![NPM version][ansi-colorsNPMVersionImage]][ansi-colorsNPMUrl]
2525
[async][asyncGHUrl] | [Documentation][asyncDOCUrl] | [![NPM version][asyncNPMVersionImage]][asyncNPMUrl]
2626
[aws-sdk][aws-sdkGHUrl] | [Documentation][aws-sdkDOCUrl] | [![NPM version][aws-sdkNPMVersionImage]][aws-sdkNPMUrl]
27-
[base62][base62GHUrl] | [Documentation][base62DOCUrl] | [![NPM version][base62NPMVersionImage]][base62NPMUrl]
2827
[body-parser][body-parserGHUrl] | [Documentation][body-parserDOCUrl] | [![NPM version][body-parserNPMVersionImage]][body-parserNPMUrl]
2928
[bootstrap][bootstrapGHUrl] | [Documentation][bootstrapDOCUrl] | [![NPM version][bootstrapNPMVersionImage]][bootstrapNPMUrl]
3029
[bootstrap-markdown][bootstrap-markdownGHUrl] | [Documentation][bootstrap-markdownDOCUrl] | [![NPM version][bootstrap-markdownNPMVersionImage]][bootstrap-markdownNPMUrl]
@@ -147,11 +146,6 @@ Outdated dependencies list can also be achieved with `$ npm outdated`
147146
[aws-sdkNPMUrl]: https://www.npmjs.com/package/aws-sdk
148147
[aws-sdkNPMVersionImage]: https://img.shields.io/npm/v/aws-sdk.svg?style=flat
149148

150-
[base62GHUrl]: https://github.com/base62/base62.js
151-
[base62DOCUrl]: https://github.com/base62/base62.js/blob/master/Readme.md
152-
[base62NPMUrl]: https://www.npmjs.com/package/base62
153-
[base62NPMVersionImage]: https://img.shields.io/npm/v/base62.svg?style=flat
154-
155149
[body-parserGHUrl]: https://github.com/expressjs/body-parser
156150
[body-parserDOCUrl]: https://github.com/expressjs/body-parser/blob/master/README.md
157151
[body-parserNPMUrl]: https://www.npmjs.com/package/body-parser

controllers/scriptStorage.js

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ var mediaType = require('media-type');
2727
var mediaDB = require('mime-db');
2828
var async = require('async');
2929
var moment = require('moment');
30-
var Base62 = require('base62/lib/ascii');
3130
var SPDX = require('spdx-license-ids');
3231
var sizeOf = require('image-size');
3332
var ipRangeCheck = require("ip-range-check");
@@ -570,6 +569,7 @@ exports.sendScript = function (aReq, aRes, aNext) {
570569

571570
var lastModified = null;
572571
var eTag = null;
572+
var hashSRI = null;
573573
var maxAge = 7 * 60 * 60 * 24; // nth day(s) in seconds
574574
var now = null;
575575
var continuation = true;
@@ -628,6 +628,10 @@ exports.sendScript = function (aReq, aRes, aNext) {
628628
}
629629
}
630630

631+
hashSRI = aScript.hash
632+
? 'sha512-' + Buffer.from(aScript.hash).toString('base64')
633+
: 'undefined';
634+
631635
// HTTP/1.1 Caching
632636
aRes.set('Cache-Control', 'public, max-age=' + maxAge +
633637
', no-cache, no-transform, must-revalidate');
@@ -639,8 +643,8 @@ exports.sendScript = function (aReq, aRes, aNext) {
639643
lastModified = moment(aScript.updated)
640644
.utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT';
641645

642-
// Convert a based representation of the hex sha512sum
643-
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .user.js"';
646+
// Use SRI of the stored sha512sum
647+
eTag = '"' + hashSRI + ' .user.js"';
644648

645649
// If already client-side... HTTP/1.1 Caching
646650
if (aReq.get('if-none-match') === eTag || aReq.get('if-modified-since') === lastModified) {
@@ -796,10 +800,12 @@ exports.sendScript = function (aReq, aRes, aNext) {
796800
} else {
797801
source = result.code;
798802

799-
// Calculate a based representation of the hex sha512sum
800-
eTag = '"' + Base62.encode(
801-
parseInt('0x' + crypto.createHash('sha512').update(source).digest('hex'), 16)) +
802-
' .min.user.js"';
803+
// Calculate SRI of the source sha512sum
804+
eTag = '"sha512-' +
805+
Buffer.from(
806+
crypto.createHash('sha512').update(source).digest('hex')
807+
).toString('base64') + ' .min.user.js"';
808+
803809
}
804810
} catch (aE) { // On any failure default to unminified
805811
if (isDev) {
@@ -827,8 +833,8 @@ exports.sendScript = function (aReq, aRes, aNext) {
827833
lastModified = moment(aScript.updated)
828834
.utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT';
829835

830-
// Reset to convert a based representation of the hex sha512sum
831-
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .user.js"';
836+
// Reset SRI of the stored sha512sum
837+
eTag = '"' + hashSRI + ' .user.js"';
832838
}
833839

834840
// If already client-side... partial HTTP/1.1 Caching
@@ -928,8 +934,8 @@ exports.sendMeta = function (aReq, aRes, aNext) {
928934
meta = script.meta; // NOTE: Watchpoint
929935

930936
if (/\.json$/.test(aReq.params.scriptname)) {
931-
// Create a based representation of the hex sha512sum
932-
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .meta.json"';
937+
// Use SRI of the stored sha512sum
938+
eTag = '"' + script.hashSRI + ' .meta.json"';
933939

934940
// If already client-side... HTTP/1.1 Caching
935941
if (aReq.get('if-none-match') === eTag) {
@@ -955,7 +961,7 @@ exports.sendMeta = function (aReq, aRes, aNext) {
955961
// Overwrite any keys found with the following...
956962
meta.OpenUserJS.installs = [{ value: script.installs }];
957963
meta.OpenUserJS.issues = [{ value: 'n/a' }];
958-
meta.OpenUserJS.hash = aScript.hash ? [{ value: aScript.hash }] : undefined;
964+
meta.OpenUserJS.hash = script.hash ? [{ value: script.hashSRI }] : 'undefined';
959965

960966
// Get the number of open issues
961967
scriptOpenIssueCountQuery = Discussion.find({ category: exports
@@ -966,8 +972,8 @@ exports.sendMeta = function (aReq, aRes, aNext) {
966972
async.parallel(tasks, asyncComplete);
967973

968974
} else {
969-
// Create a based representation of the hex sha512sum
970-
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + ' .meta.js"';
975+
// Use SRI of the stored sha512sum
976+
eTag = '"' + script.hashSRI + ' .meta.js"';
971977

972978
// If already client-side... HTTP/1.1 Caching
973979
if (aReq.get('if-none-match') === eTag) {

libs/modelParser.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,14 @@ var parseScript = function (aScript) {
489489
parseDateProperty(script, 'updated');
490490

491491
// Hash
492-
script.hashShort = script.hash ? script.hash.substr(0, 7) : 'undefined';
492+
script.hashShort = 'undefined';
493+
script.hashSRI = 'undefined';
494+
495+
if (script.hash) {
496+
// NOTE: May be absent in dev DB but should not be in pro DB
497+
script.hashShort = script.hash.substr(0, 7);
498+
script.hashSRI = 'sha512-' + Buffer.from(script.hash).toString('base64');
499+
}
493500

494501
if (script.created && script.updated && script.created.toString() !== script.updated.toString()) {
495502
script.isUpdated = true;

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"async": "3.2.0",
1010
"@octokit/auth-oauth-app": "4.3.0",
1111
"aws-sdk": "2.944.0",
12-
"base62": "2.0.1",
1312
"body-parser": "1.19.0",
1413
"bootstrap": "3.4.1",
1514
"bootstrap-markdown": "2.10.0",

views/pages/scriptPage.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
<div class="script-meta">
2929
<p><i class="fa fa-fw fa-clock-o"></i> <b>Published:</b> <time datetime="{{script.createdISOFormat}}" title="{{script.created}}">{{script.createdHumanized}}</time></p>
30-
<p><i class="fa fa-fw fa-history"></i> <b>Version:</b> <code>{{script.meta.UserScript.version.0.value}}<span title="SHA-512 {{script.hash}}">+{{script.hashShort}}</span></code>{{#script.isUpdated}} updated <time class="script-updated" datetime="{{script.updatedISOFormat}}" title="{{script.updated}}">{{script.updatedHumanized}}</time>{{/script.isUpdated}}</p>
30+
<p><i class="fa fa-fw fa-history"></i> <b>Version:</b> <code>{{script.meta.UserScript.version.0.value}}<span title="{{script.hashSRI}}">+{{script.hashShort}}</span></code>{{#script.isUpdated}} updated <time class="script-updated" datetime="{{script.updatedISOFormat}}" title="{{script.updated}}">{{script.updatedHumanized}}</time>{{/script.isUpdated}}</p>
3131
{{#script.description}}<p><i class="fa fa-fw fa-info"></i> <b>Summary:</b> {{script.description}}</p>{{/script.description}}
3232
{{#script.hasGroups}}
3333
<span>

0 commit comments

Comments
 (0)