Hi,
I’ve been trying to implement the following javascript code provided by Cloudflare to generate tokens to secure video streams (Secure your Stream · Cloudflare Stream docs)
// Main function
async function streamSignedUrl () {
const encoder = new TextEncoder()
const expiresIn = Math.floor(Date.now() / 1000) + expiresTimeInS
const headers = {
"alg": "RS256",
"kid": keyID
}
const data = {
"sub": videoUID,
"kid": keyID,
"exp": expiresIn,
"accessRules": [
{
"type": "ip.geoip.country",
"action": "allow",
"country": [
"GB"
]
},
{
"type": "any",
"action": "block"
}
]
}
const token = `${objectToBase64url(headers)}.${objectToBase64url(data)}`
const jwk = JSON.parse(atob(jwkKey))
const key = await crypto.subtle.importKey(
"jwk", jwk,
{
name: 'RSASSA-PKCS1-v1_5',
hash: 'SHA-256',
},
false, [ "sign" ]
)
const signature = await crypto.subtle.sign(
{ name: 'RSASSA-PKCS1-v1_5' }, key,
encoder.encode(token)
)
const signedToken = `${token}.${arrayBufferToBase64Url(signature)}`
return signedToken
}
// Utilities functions
function arrayBufferToBase64Url(buffer) {
return btoa(String.fromCharCode(...new Uint8Array(buffer)))
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_')
}
function objectToBase64url(payload) {
return arrayBufferToBase64Url(
new TextEncoder().encode(JSON.stringify(payload)),
)
}
I was able to produce the token
variable successfully by comparing the outputs of the javascript code with the output I generate on my elixir code, and then produce the same object assigned to jwk
variable in the shape of a elixir map, but then I got got stuck.
I don’t quite understand what would be the equivalent (if there is one) in Elixir for what is produced by crypto.subtle.importKey
and crypto.subtle.sign
.
crypto.subtle.importKey
returns a CryptoKey
object that can be used as argument in crypto.subtle.sign
but I couldn’t find elixir/erlang counterpart for this.
Could anyone give me some guidance on how to proceed or where to get more information on this?
I don’t even know what to lookup.
Thanks!