Skip to content

Commit

Permalink
Support signed URLs in IIIF requests
Browse files Browse the repository at this point in the history
  • Loading branch information
kdid committed Oct 11, 2024
1 parent 8a11223 commit 355b5ac
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 1 deletion.
74 changes: 73 additions & 1 deletion iiif-server/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
const authorize = require("./authorize");
const jwt = require('jsonwebtoken');
const querystring = require('querystring');

const middy = require("@middy/core");
const secretsManager = require("@middy/secrets-manager");

const API_TOKEN_KEY = process.env.API_TOKEN_KEY

function getEventHeader(request, name) {
if (
request.headers &&
Expand Down Expand Up @@ -47,22 +52,89 @@ function parsePath(path) {
filename: segments[0]
};
} else {
const filename = segments[0].split(".");
return {
poster: segments[5] == "posters",
id: segments[4],
region: segments[3],
size: segments[2],
rotation: segments[1],
filename: segments[0]
filename: segments[0],
quality: filename[0],
format: filename[1]
};
}
}

function getAuthSignature(request) {
if (!request.querystring) {
return null;
}

const parsedQuery = querystring.parse(request.querystring);
return parsedQuery['Auth-Signature'] || null;
}

function validateJwtClaims(jwtClaims, params) {
const currentTime = Math.floor(Date.now() / 1000);

if (jwtClaims.expires <= currentTime) {
return false;
}

if (jwtClaims.id !== params.id) {
return false;
}

const fields = ['region', 'size', 'rotation', 'quality', 'format'];
for (const field of fields) {
if (jwtClaims[field] && !jwtClaims[field].includes(params[field])) {
return false;
}
}

if (jwtClaims['max-width'] && params.size.width > jwtClaims['max-width']) {
return false;
}

if (jwtClaims['max-height'] && params.size.height > jwtClaims['max-height']) {
return false;
}

return true;
}

async function viewerRequestIiif(request, { config }) {
const path = decodeURI(request.uri.replace(/%2f/gi, ""));
const params = parsePath(path);
const referer = getEventHeader(request, "referer");
const cookie = getEventHeader(request, "cookie");
const authSignature = getAuthSignature(request);

if(authSignature) {
console.log("Verifying JWT")
let jwtClaims;
try {
jwtClaims = jwt.verify(authSignature, API_TOKEN_KEY);
} catch (err) {
console.log(err)
return {
status: "403",
statusDescription: "Forbidden",
body: "Invalid JWT"
};
}

if (!validateJwtClaims(jwtClaims, params)) {
console.log("Could not verify JWT claims")
return {
status: "403",
statusDescription: "Forbidden",
body: "Forbidden"
};
}
}

const authed = await authorize(
params,
referer,
Expand Down
213 changes: 213 additions & 0 deletions iiif-server/src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions iiif-server/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dependencies": {
"@middy/core": "4.6.4",
"@middy/secrets-manager": "4.6.4",
"jsonwebtoken": "^9.0.2",
"lodash.isstring": "^4.0.1",
"node-fetch": "^2.3.0"
}
Expand Down
3 changes: 3 additions & 0 deletions iiif-server/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Parameters:
AllowFromReferers:
Type: String
Default: ""
ApiTokenKey:
Type: String
CertificateArn:
Type: String
DcApiEndpoint:
Expand Down Expand Up @@ -79,6 +81,7 @@ Resources:
allowFrom: !Ref AllowFromReferers
dcApiEndpoint: !Ref DcApiEndpoint
tiffBucket: !Ref SourceBucket
apiTokenKey: !Ref ApiTokenKey
ViewerRequestSecretAccess:
Type: AWS::SecretsManager::ResourcePolicy
Properties:
Expand Down

0 comments on commit 355b5ac

Please sign in to comment.