admin管理员组文章数量:1122832
I'm having trouble generating a valid signed URL with NodeJS for Google Cloud Media CDN.
The goal is to generate a signed URL with NodeJS and the URL to expire after 10 minutes.
The issue is bizarre for some specific expiration timestamp it work and for most do not work. In the NodeJS example I have two timestamps for one it work and for other do not work.
My configuration of the Media CDN, appears correct. I was trying to debug it with the Python examples and there it work like a charm, no issue there regardless of expiration time. I was trying to reuse the Python generated keys in the NodeJS example, however looks like the RAW Ed25519 private key is not supported.
For Python generated Ed25519 keys I used this example from Google docs
and for the NodeJS example I used the keys generated by command line example from Google docs
For generating a signed URL with Python I use the example from here
This is the Python example that works every time with the keys generated from the Python script
import base64
import datetime
import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519
from six.moves import urllib
def sign_url(
url: str, key_name: str, base64_key: str, expiration_time: datetime.datetime
) -> str:
"""Gets the Signed URL string for the specified URL and configuration.
Args:
url: URL to sign as a string.
key_name: name of the signing key as a string.
base64_key: signing key as a base64 encoded byte string.
expiration_time: expiration time as a UTC datetime object.
Returns:
Returns the Signed URL appended with the query parameters based on the
specified configuration.
"""
stripped_url = url.strip()
parsed_url = urllib.parse.urlsplit(stripped_url)
query_params = urllib.parse.parse_qs(parsed_url.query, keep_blank_values=True)
epoch = datetime.datetime.utcfromtimestamp(0)
expiration_timestamp = int((expiration_time - epoch).total_seconds())
decoded_key = base64.urlsafe_b64decode(base64_key)
url_pattern = "{url}{separator}Expires={expires}&KeyName={key_name}"
url_to_sign = url_pattern.format(
url=stripped_url,
separator="&" if query_params else "?",
expires=expiration_timestamp,
key_name=key_name,
)
digest = ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key).sign(
url_to_sign.encode("utf-8")
)
signature = base64.urlsafe_b64encode(digest).decode("utf-8")
signed_url = "{url}&Signature={signature}".format(
url=url_to_sign, signature=signature
)
return signed_url
# private key: tHfW65gTzws54calc2OzICdVvdu6X1BoonVLjsD5ZQU=
# public key: 5xujsWltI4LTi0Q92hp9HmA03KsJFn2WwziiOA3POm8=
url = '/raindrops.mp4'
key_name = 'dev-keyset'
private_key = 'tHfW65gTzws54calc2OzICdVvdu6X1BoonVLjsD5ZQU='
expiration_timestamp = datetime.datetime.now() + datetime.timedelta(minutes = 10)
result = sign_url(url, key_name, private_key, expiration_timestamp)
print(result)
Signed URL with Python
And this is my NodeJS script for signing
const crypto = require('crypto');
// private key: MC4CAQAwBQYDK2VwBCIEIPzuffDsZ43sPxf1fuwiDrKsiSoyFw8aosF2jhS3VCez
// public key: JU4ouYJAZvD12RYH8-zhSmUTqT1ohN-1kcIKhr2jL4o=
function signURL(url, expiresTs, keyName, privateKey) {
const toSign = `${url}?Expires=${expiresTs}&KeyName=${keyName}`;
const signature = crypto.sign(null, Buffer.from(toSign), privateKey);
return `${toSign}&Signature=${signature.toString('base64')}`;
}
const privateKey = crypto.createPrivateKey({
key: Buffer.from('MC4CAQAwBQYDK2VwBCIEIPzuffDsZ43sPxf1fuwiDrKsiSoyFw8aosF2jhS3VCez', 'base64'),
format: 'der',
type: 'pkcs8',
});
const url = '/raindrops.mp4';
const expiresTs = Math.round(new Date().getTime() / 1000) + 10 * 60; // ten minutes after now, in seconds.
// const expiresTs = 1735689598; // 2024-12-31 23:59:58 - do not work. The response is 'Google-Edge-Cache: Invalid signed request Error: 114'
// const expiresTs = 1735689599; // 2024-12-31 23:59:59 - work
const keyName = 'dev-keyset';
const signedUrl = signURL(url, expiresTs, keyName, privateKey);
console.log(signedUrl);
Signed URL with NodeJS The response is: Google-Edge-Cache: Invalid signed request Error: 114
I guess the problem is in my NodeJS script. Currently, I'm not sure where the problem is and what I should try. Any help or guideline would be appreciated.
I'm having trouble generating a valid signed URL with NodeJS for Google Cloud Media CDN.
The goal is to generate a signed URL with NodeJS and the URL to expire after 10 minutes.
The issue is bizarre for some specific expiration timestamp it work and for most do not work. In the NodeJS example I have two timestamps for one it work and for other do not work.
My configuration of the Media CDN, appears correct. I was trying to debug it with the Python examples and there it work like a charm, no issue there regardless of expiration time. I was trying to reuse the Python generated keys in the NodeJS example, however looks like the RAW Ed25519 private key is not supported.
For Python generated Ed25519 keys I used this example from Google docs
and for the NodeJS example I used the keys generated by command line example from Google docs
For generating a signed URL with Python I use the example from here
This is the Python example that works every time with the keys generated from the Python script
import base64
import datetime
import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519
from six.moves import urllib
def sign_url(
url: str, key_name: str, base64_key: str, expiration_time: datetime.datetime
) -> str:
"""Gets the Signed URL string for the specified URL and configuration.
Args:
url: URL to sign as a string.
key_name: name of the signing key as a string.
base64_key: signing key as a base64 encoded byte string.
expiration_time: expiration time as a UTC datetime object.
Returns:
Returns the Signed URL appended with the query parameters based on the
specified configuration.
"""
stripped_url = url.strip()
parsed_url = urllib.parse.urlsplit(stripped_url)
query_params = urllib.parse.parse_qs(parsed_url.query, keep_blank_values=True)
epoch = datetime.datetime.utcfromtimestamp(0)
expiration_timestamp = int((expiration_time - epoch).total_seconds())
decoded_key = base64.urlsafe_b64decode(base64_key)
url_pattern = "{url}{separator}Expires={expires}&KeyName={key_name}"
url_to_sign = url_pattern.format(
url=stripped_url,
separator="&" if query_params else "?",
expires=expiration_timestamp,
key_name=key_name,
)
digest = ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key).sign(
url_to_sign.encode("utf-8")
)
signature = base64.urlsafe_b64encode(digest).decode("utf-8")
signed_url = "{url}&Signature={signature}".format(
url=url_to_sign, signature=signature
)
return signed_url
# private key: tHfW65gTzws54calc2OzICdVvdu6X1BoonVLjsD5ZQU=
# public key: 5xujsWltI4LTi0Q92hp9HmA03KsJFn2WwziiOA3POm8=
url = 'https://media.radixsoft.dev/raindrops.mp4'
key_name = 'dev-keyset'
private_key = 'tHfW65gTzws54calc2OzICdVvdu6X1BoonVLjsD5ZQU='
expiration_timestamp = datetime.datetime.now() + datetime.timedelta(minutes = 10)
result = sign_url(url, key_name, private_key, expiration_timestamp)
print(result)
Signed URL with Python
And this is my NodeJS script for signing
const crypto = require('crypto');
// private key: MC4CAQAwBQYDK2VwBCIEIPzuffDsZ43sPxf1fuwiDrKsiSoyFw8aosF2jhS3VCez
// public key: JU4ouYJAZvD12RYH8-zhSmUTqT1ohN-1kcIKhr2jL4o=
function signURL(url, expiresTs, keyName, privateKey) {
const toSign = `${url}?Expires=${expiresTs}&KeyName=${keyName}`;
const signature = crypto.sign(null, Buffer.from(toSign), privateKey);
return `${toSign}&Signature=${signature.toString('base64')}`;
}
const privateKey = crypto.createPrivateKey({
key: Buffer.from('MC4CAQAwBQYDK2VwBCIEIPzuffDsZ43sPxf1fuwiDrKsiSoyFw8aosF2jhS3VCez', 'base64'),
format: 'der',
type: 'pkcs8',
});
const url = 'https://media.radixsoft.dev/raindrops.mp4';
const expiresTs = Math.round(new Date().getTime() / 1000) + 10 * 60; // ten minutes after now, in seconds.
// const expiresTs = 1735689598; // 2024-12-31 23:59:58 - do not work. The response is 'Google-Edge-Cache: Invalid signed request Error: 114'
// const expiresTs = 1735689599; // 2024-12-31 23:59:59 - work
const keyName = 'dev-keyset';
const signedUrl = signURL(url, expiresTs, keyName, privateKey);
console.log(signedUrl);
Signed URL with NodeJS The response is: Google-Edge-Cache: Invalid signed request Error: 114
I guess the problem is in my NodeJS script. Currently, I'm not sure where the problem is and what I should try. Any help or guideline would be appreciated.
Share Improve this question edited Nov 22, 2024 at 14:57 Hristo Hristov asked Nov 22, 2024 at 14:50 Hristo HristovHristo Hristov 195 bronze badges1 Answer
Reset to default 2You need to use URL-safe Base64 encoding. In your NodeJS code, change signature.toString('base64')
to signature.toString('base64url')
.
本文标签: nodejsHow to create a signed URL in NodeJS for Google Cloud Media CDNStack Overflow
版权声明:本文标题:node.js - How to create a signed URL in NodeJS for Google Cloud Media CDN - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736303036a1931745.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论