Skip to content

Commit 2de792a

Browse files
author
Amir Tocker
committed
Add Akamai token generator
1 parent f6d5c58 commit 2de792a

File tree

5 files changed

+59
-2
lines changed

5 files changed

+59
-2
lines changed

lib/utils.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/utils.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/generateAkamaiToken.coffee

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
crypto = require('crypto')
2+
config = require('./config')
3+
4+
digest = (message, key) ->
5+
crypto.createHmac("sha256", new Buffer(key, "hex"))
6+
.update message
7+
.digest 'hex'
8+
9+
10+
module.exports = generateAkamaiToken = (options)->
11+
key = options.key ? config().akamai_key
12+
tokenName = options.token_name ? "__cld_token__"
13+
expiration = options.end_time
14+
unless expiration?
15+
if options.window?
16+
start = options.start_time ? Math.round(Date.now() / 1000)
17+
expiration = start + options.window
18+
else
19+
throw new Error( "Must provide either end_time or window")
20+
21+
tokenParts = []
22+
tokenParts.push("ip=#{options.ip}") if options.ip?
23+
tokenParts.push("st=#{options.start_time}") if options.start_time?
24+
tokenParts.push("exp=#{expiration}")
25+
tokenParts.push("acl=#{options.acl}")
26+
auth = digest(tokenParts.join("~"), key)
27+
tokenParts.push("hmac=#{auth}")
28+
"#{tokenName}=#{tokenParts.join('~')}"

src/utils.coffee

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ config = require("./config")
33
crypto = require('crypto')
44
querystring = require('querystring')
55
utils = exports
6-
6+
exports.generateAkamaiToken = require("./generateAkamaiToken")
77
exports.CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net"
88
exports.OLD_AKAMAI_SHARED_CDN = "cloudinary-a.akamaihd.net"
99
exports.AKAMAI_SHARED_CDN = "res.cloudinary.com"

test/utils_spec.coffee

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,3 +573,30 @@ describe "utils", ->
573573
"if": "w = 0 && height != 0 || aspectRatio < 0 and pageCount > 0 and faceCount <= 0 and width >= 0",
574574
"effect": "grayscale",
575575
)).to.match(new RegExp(allOperators))
576+
577+
describe 'generateAkamaiToken', ->
578+
beforeEach ->
579+
cloudinary.config( akamai_key: '00112233FF99')
580+
afterEach ->
581+
cloudinary.config(true)
582+
583+
it "should generate an Akamai token with start_time and window", ->
584+
token = utils.generateAkamaiToken start_time: 1111111111, acl: '/image/*', window: 300
585+
expect(token).to.eql('__cld_token__=st=1111111111~exp=1111111411~acl=/image/*~hmac=0854e8b6b6a46471a80b2dc28c69bd352d977a67d031755cc6f3486c121b43af')
586+
it "should generate an Akamai token with window", ->
587+
first_exp = Math.round(Date.now() / 1000 )+ 300
588+
# expiration is calculated automatically as now + window
589+
token = utils.generateAkamaiToken acl: '*', window: 300
590+
second_exp = Math.round(Date.now() / 1000 )+ 300
591+
match = /exp=(\d+)/.exec(token)
592+
expect(match[1]).to.be.ok()
593+
expiration = parseInt(match[1])
594+
expect(expiration).to.be.within(first_exp, second_exp)
595+
expect(utils.generateAkamaiToken acl: '*', end_time: expiration).to.eql(token)
596+
597+
it "should accept a key", ->
598+
expect(utils.generateAkamaiToken acl: '*', end_time: 10000000, key: '00aabbff')
599+
.to.eql('__cld_token__=exp=10000000~acl=*~hmac=030eafb6b19e499659d699b3d43e7595e35e3c0060e8a71904b3b8c8759f4890')
600+
601+
it "should throw if no end_time or window is provided", ->
602+
expect( -> utils.generateAkamaiToken( acl: '*') ).to.throwError()

0 commit comments

Comments
 (0)