Use @misskey-dev/node-http-message-signatures

In the future, it will allow us to:
 * Sign using RFC 9421
 * Accept RFC 9421 signatures
 * Support RFC 3230 and RFC 9530 digests
 * Use Ed25519 keys
This commit is contained in:
Chocobozzz
2025-12-18 11:59:15 +01:00
parent 075bd106ce
commit defaaaf026
13 changed files with 150 additions and 183 deletions
+1 -1
View File
@@ -95,6 +95,7 @@
"@aws-sdk/s3-request-presigner": "^3.930.0",
"@commander-js/extra-typings": "^14.0.0",
"@jimp/plugin-color": "^1.6.0",
"@misskey-dev/node-http-message-signatures": "^0.0.10",
"@node-oauth/oauth2-server": "^5.2.1",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-jaeger": "^2.2.0",
@@ -113,7 +114,6 @@
"@opentelemetry/semantic-conventions": "^1.38.0",
"@peertube/bittorrent-tracker-server": "^11.1.2",
"@peertube/feed": "^5.4.1",
"@peertube/http-signature": "^1.7.0",
"@peertube/peertube-core-utils": "workspace:*",
"@peertube/peertube-ffmpeg": "workspace:*",
"@peertube/peertube-models": "workspace:*",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjQGdH6D3naKmSbbr/Df\nEh1H42F3WlHYXuxKLkm5Bemjdde+GwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYO\nwAyc3Zoy7afPNa4bZXqhJ1Im41rMGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55s\nIkczDkseJuadTvG+A1e4uNY2lnRmVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/F\npP5S75TS5l1DfJQIq2lp8RwrH6FvGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM\n7mS7eP8zF8lKXYUu8cjIscKm+XqGmyRoPyw2Pp53tew29idRUocVQHGBnlNbpKdd\naQIDAQAB\n-----END PUBLIC KEY-----\n",
"privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqjQGdH6D3naKmSbbr/DfEh1H42F3WlHYXuxKLkm5Bemjdde+\nGwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYOwAyc3Zoy7afPNa4bZXqhJ1Im41rM\nGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55sIkczDkseJuadTvG+A1e4uNY2lnRm\nVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/FpP5S75TS5l1DfJQIq2lp8RwrH6Fv\nGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM7mS7eP8zF8lKXYUu8cjIscKm+XqG\nmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKddaQIDAQABAoIBAQCnBZawCtbtH/ay\ng+dhqEW/SOyavbKZ92cU/1tsQPxISRYXNjdf2VfK7HmVqC2S7NqBanz+AVZPHmda\n7OfamkSvQbFN5VvEy8ATNV+9HbG3HG78/MT9hZcGigmyJkcZuy4wILgoXCxfpxlD\netla60PB/4yioiRcmEIWjjOgpByphDJ7RuuuptyEvgjUjpPtvHK47O/loaD2HFJk\nbIYbRirbjUjITRjQxGVIvanqiwPG9pB26YDLxDOoXEumcnzRcEFWNdvoleaLgquS\nn/zVsXWEq4+1i7t44DDstWUt/2Bw5ksIkSdayQ6oy3vzre3YFHwvbVZ7qtQQgpru\nx+NIolZhAoGBAN1RgNj8zy9Py3SJdsoXtnuCItfD7eo7LWXUa06cM/NS695Q+/to\naa5i3cJnRlv+b+b3VvnhkhIBLfFQW+hWwPnnxJEehcm09ddN9zbWrZ4Yv9yYu+8d\nTLGyWL8kPFF1dz+29DcrSv3tXEOwxByX/O4U/X/i3wl2WhkybxVFnCuvAoGBAMTf\n91BgLzvcYKOxH+vRPOJY7g2HKGFe35R91M4E+9Eq1rq4LUQHBb3fhRh4+scNu0yb\nNfN1Zdx2nbgCXdTKomF1Ahxp58/A2iU65vVzL6hYfWXEGSmoBqsGCIpIxQ9jgB9k\nCl7t/Ban8Z/ORHTjI9fpHlSZyCWJ3ajepiM2a1ZnAoGAPpDO6wi1DXvyWVSPF1yS\nwuGsNfD2rjPihpoBZ+yypwP3GBcu1QjUb28Vn+KQOmt4eQPNO8DwCVT6BvEfulPk\nJAHISPom+jnFEgPBcmhIFpyKiLNI1bUjvExd2FNHFgQuHP38ligQAC782Un8dtTk\ntO2MKH4bbVJe8CaYzpuqJZMCgYABZyMpBHZxs8FQiUuT75rCdiXEHOlxwC5RrY/d\no/VzaR28mOFhsbcdwkD9iqcm0fc6tYRt5rFCH+pBzGqEwKjljuLj9vE67sHfMAtD\nRn3Zcj/6gKo5PMRHZbSb36bf1DKuhpT4VjPMqYe0PtEIEDJKMJQRwELH2bKlqGiA\nqbucEwKBgQCkS85JnpHEV/tSylsEEn2W3CQCx58zl7iZNV7h/tWMR4AyrcI0HqP6\nllJ7V/Cfw66MgelPnosKgagwLVI6gsqDtjnzYo3XuMRVlYIySJ/jV3eiUNkV2Ky2\nfp/gA9sVgp38QSr+xB9E0LNStcbqDzoCCcDRws/SK7PbkQH9KV47tQ==\n-----END RSA PRIVATE KEY-----"
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqNAZ0foPedoqZ\nJtuv8N8SHUfjYXdaUdhe7EouSbkF6aN1174bAdh3Pmbd9whbDcdPN8D7L05/x6kZ\n19Ku1g7ADJzdmjLtp881rhtleqEnUibjWswaJ6IK5Sfi5M8+5wiMLSAKRXC+5Cvc\nSVuTnmwiRzMOSx4m5p1O8b4DV7i41jaWdGZWF/iDkH3S7oIt7Yp1s+mJ9GgqXD3N\npQGPj8Wk/lLvlNLmXUN8lAiraWnxHCsfoW8YoudaVsZ41hf3oMO+UDlLGjHPpr5t\nNX06ikzuZLt4/zMXyUpdhS7xyMixwqb5eoabJGg/LDc+nne17Db2J1FShxVAcYGe\nU1ukp11pAgMBAAECggEBAKcFlrAK1u0f9rKD52GoRb9I7Jq9spn3ZxT/W2xA/EhJ\nFhc2N1/ZV8rseZWoLZLs2oFqfP4BVk8eZ1rs59qaRK9BsU3lW8TLwBM1X70dsbcc\nbvz8xP2FlwaKCbImRxm7LjAguChcLF+nGUN62VrrQ8H/jKKiJFyYQhaOM6CkHKmE\nMntG666m3IS+CNSOk+28crjs7+WhoPYcUmRshhtGKtuNSMhNGNDEZUi9qeqLA8b2\nkHbpgMvEM6hcS6ZyfNFwQVY12+iV5ouCq5Kf/NWxdYSrj7WLu3jgMOy1ZS3/YHDm\nSwiRJ1rJDqjLe/Ot7dgUfC9tVnuq1BCCmu7H40iiVmECgYEA3VGA2PzPL0/LdIl2\nyhe2e4Ii18Pt6jstZdRrTpwz81Lr3lD7+2hprmLdwmdGW/5v5vdW+eGSEgEt8VBb\n6FbA+efEkR6FybT11033Ntatnhi/3Ji77x1MsbJYvyQ8UXV3P7b0NytK/e1cQ7DE\nHJf87hT9f+LfCXZaGTJvFUWcK68CgYEAxN/3UGAvO9xgo7Ef69E84ljuDYcoYV7f\nlH3UzgT70SrWurgtRAcFvd+FGHj6xw27TJs183Vl3HaduAJd1MqiYXUCHGnnz8Da\nJTrm9XMvqFh9ZcQZKagGqwYIikjFD2OAH2QKXu38Fqfxn85EdOMj1+keVJnIJYnd\nqN6mIzZrVmcCgYA+kM7rCLUNe/JZVI8XXJLC4aw18PauM+KGmgFn7LKnA/cYFy7V\nCNRvbxWf4pA6a3h5A807wPAJVPoG8R+6U+QkAchI+ib6OcUSA8FyaEgWnIqIs0jV\ntSO8TF3YU0cWBC4c/fyWKBAALvzZSfx21OS07YwofhttUl7wJpjOm6olkwKBgAFn\nIykEdnGzwVCJS5PvmsJ2JcQc6XHALlGtj92j9XNpHbyY4WGxtx3CQP2KpybR9zq1\nhG3msUIf6kHMaoTAqOWO4uP28Truwd8wC0NGfdlyP/qAqjk8xEdltJvfpt/UMq6G\nlPhWM8yph7Q+0QgQMkowlBHAQsfZsqWoaICpu5wTAoGBAKRLzkmekcRX+1LKWwQS\nfZbcJALHnzOXuJk1XuH+1YxHgDKtwjQeo/qWUntX8J/DroyB6U+eiwqBqDAtUjqC\nyoO2OfNijde4xFWVgjJIn+NXd6JQ2RXYrLZ+n+AD2xWCnfxBKv7EH0TQs1K1xuoP\nOgIJwNHCz9Irs9uRAf0pXju1\n-----END PRIVATE KEY-----\n"
}
+1 -1
View File
@@ -1,4 +1,4 @@
{
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjQGdH6D3naKmSbbr/Df\nEh1H42F3WlHYXuxKLkm5Bemjdde+GwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYO\nwAyc3Zoy7afPNa4bZXqhJ1Im41rMGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55s\nIkczDkseJuadTvG+A1e4uNY2lnRmVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/F\npP5S75TS5l1DfJQIq2lp8RwrH6FvGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM\n7mS7eP8zF8lKXYUu8cjIscKm+XqGmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKdd\naQIDAQAB\n-----END PUBLIC KEY-----\n",
"privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqjQGdH6D3naKmSbbr/DfEh1H42F3WlHYXuxKLkm5Bemjdde+\nGwHYdz5m3fcIWw3HTzfA+y9Of8epGdfSrtYOwAyc3Zoy7afPNa4bZXqhJ1Im41rM\nGieiCuUn4uTPPucIjC0gCkVwvuQr3Elbk55sIkczDkseJuadTvG+A1e4uNY2lnRm\nVhf4g5B90u6CLe2KdbPpifRoKlw9zaUBj4/FpP5S75TS5l1DfJQIq2lp8RwrH6Fv\nGKLnWlbGeNYX96DDvlA5Sxoxz6a+bTV9OopM7mS7eP8zF8lKXYUu8cjIscKm+XqG\nmyRoPyw3Pp53tew29idRUocVQHGBnlNbpKddaQIDAQABAoIBAQCnBZawCtbtH/ay\ng+dhqEW/SOyavbKZ92cU/1tsQPxISRYXNjdf2VfK7HmVqC2S7NqBanz+AVZPHmda\n7OfamkSvQbFN5VvEy8ATNV+9HbG3HG78/MT9hZcGigmyJkcZuy4wILgoXCxfpxlD\netla60PB/4yioiRcmEIWjjOgpByphDJ7RuuuptyEvgjUjpPtvHK47O/loaD2HFJk\nbIYbRirbjUjITRjQxGVIvanqiwPG9pB26YDLxDOoXEumcnzRcEFWNdvoleaLgquS\nn/zVsXWEq4+1i7t44DDstWUt/2Bw5ksIkSdayQ6oy3vzre3YFHwvbVZ7qtQQgpru\nx+NIolZhAoGBAN1RgNj8zy9Py3SJdsoXtnuCItfD7eo7LWXUa06cM/NS695Q+/to\naa5i3cJnRlv+b+b3VvnhkhIBLfFQW+hWwPnnxJEehcm09ddN9zbWrZ4Yv9yYu+8d\nTLGyWL8kPFF1dz+29DcrSv3tXEOwxByX/O4U/X/i3wl2WhkybxVFnCuvAoGBAMTf\n91BgLzvcYKOxH+vRPOJY7g2HKGFe35R91M4E+9Eq1rq4LUQHBb3fhRh4+scNu0yb\nNfN1Zdx2nbgCXdTKomF1Ahxp58/A2iU65vVzL6hYfWXEGSmoBqsGCIpIxQ9jgB9k\nCl7t/Ban8Z/ORHTjI9fpHlSZyCWJ3ajepiM2a1ZnAoGAPpDO6wi1DXvyWVSPF1yS\nwuGsNfD2rjPihpoBZ+yypwP3GBcu1QjUb28Vn+KQOmt4eQPNO8DwCVT6BvEfulPk\nJAHISPom+jnFEgPBcmhIFpyKiLNI1bUjvExd2FNHFgQuHP38ligQAC782Un8dtTk\ntO2MKH4bbVJe8CaYzpuqJZMCgYABZyMpBHZxs8FQiUuT75rCdiXEHOlxwC5RrY/d\no/VzaR28mOFhsbcdwkD9iqcm0fc6tYRt5rFCH+pBzGqEwKjljuLj9vE67sHfMAtD\nRn3Zcj/6gKo5PMRHZbSb36bf1DKuhpT4VjPMqYe0PtEIEDJKMJQRwELH2bKlqGiA\nqbucEwKBgQCkS85JnpHEV/tSylsEEn2W3CQCx58zl7iZNV7h/tWMR4AyrcI0HqP6\nllJ7V/Cfw66MgelPnosKgagwLVI6gsqDtjnzYo3XuMRVlYIySJ/jV3eiUNkV2Ky2\nfp/gA9sVgp38QSr+xB9E0LNStcbqDzoCCcDRws/SK7PbkQH9KV47tQ==\n-----END RSA PRIVATE KEY-----"
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqNAZ0foPedoqZ\nJtuv8N8SHUfjYXdaUdhe7EouSbkF6aN1174bAdh3Pmbd9whbDcdPN8D7L05/x6kZ\n19Ku1g7ADJzdmjLtp881rhtleqEnUibjWswaJ6IK5Sfi5M8+5wiMLSAKRXC+5Cvc\nSVuTnmwiRzMOSx4m5p1O8b4DV7i41jaWdGZWF/iDkH3S7oIt7Yp1s+mJ9GgqXD3N\npQGPj8Wk/lLvlNLmXUN8lAiraWnxHCsfoW8YoudaVsZ41hf3oMO+UDlLGjHPpr5t\nNX06ikzuZLt4/zMXyUpdhS7xyMixwqb5eoabJGg/LDc+nne17Db2J1FShxVAcYGe\nU1ukp11pAgMBAAECggEBAKcFlrAK1u0f9rKD52GoRb9I7Jq9spn3ZxT/W2xA/EhJ\nFhc2N1/ZV8rseZWoLZLs2oFqfP4BVk8eZ1rs59qaRK9BsU3lW8TLwBM1X70dsbcc\nbvz8xP2FlwaKCbImRxm7LjAguChcLF+nGUN62VrrQ8H/jKKiJFyYQhaOM6CkHKmE\nMntG666m3IS+CNSOk+28crjs7+WhoPYcUmRshhtGKtuNSMhNGNDEZUi9qeqLA8b2\nkHbpgMvEM6hcS6ZyfNFwQVY12+iV5ouCq5Kf/NWxdYSrj7WLu3jgMOy1ZS3/YHDm\nSwiRJ1rJDqjLe/Ot7dgUfC9tVnuq1BCCmu7H40iiVmECgYEA3VGA2PzPL0/LdIl2\nyhe2e4Ii18Pt6jstZdRrTpwz81Lr3lD7+2hprmLdwmdGW/5v5vdW+eGSEgEt8VBb\n6FbA+efEkR6FybT11033Ntatnhi/3Ji77x1MsbJYvyQ8UXV3P7b0NytK/e1cQ7DE\nHJf87hT9f+LfCXZaGTJvFUWcK68CgYEAxN/3UGAvO9xgo7Ef69E84ljuDYcoYV7f\nlH3UzgT70SrWurgtRAcFvd+FGHj6xw27TJs183Vl3HaduAJd1MqiYXUCHGnnz8Da\nJTrm9XMvqFh9ZcQZKagGqwYIikjFD2OAH2QKXu38Fqfxn85EdOMj1+keVJnIJYnd\nqN6mIzZrVmcCgYA+kM7rCLUNe/JZVI8XXJLC4aw18PauM+KGmgFn7LKnA/cYFy7V\nCNRvbxWf4pA6a3h5A807wPAJVPoG8R+6U+QkAchI+ib6OcUSA8FyaEgWnIqIs0jV\ntSO8TF3YU0cWBC4c/fyWKBAALvzZSfx21OS07YwofhttUl7wJpjOm6olkwKBgAFn\nIykEdnGzwVCJS5PvmsJ2JcQc6XHALlGtj92j9XNpHbyY4WGxtx3CQP2KpybR9zq1\nhG3msUIf6kHMaoTAqOWO4uP28Truwd8wC0NGfdlyP/qAqjk8xEdltJvfpt/UMq6G\nlPhWM8yph7Q+0QgQMkowlBHAQsfZsqWoaICpu5wTAoGBAKRLzkmekcRX+1LKWwQS\nfZbcJALHnzOXuJk1XuH+1YxHgDKtwjQeo/qWUntX8J/DroyB6U+eiwqBqDAtUjqC\nyoO2OfNijde4xFWVgjJIn+NXd6JQ2RXYrLZ+n+AD2xWCnfxBKv7EH0TQs1K1xuoP\nOgIJwNHCz9Irs9uRAf0pXju1\n-----END PRIVATE KEY-----\n"
}
@@ -73,8 +73,6 @@ async function makeFollowRequest (to: { url: string }, by: { url: string, privat
const body = await activityPubContextify(follow, 'Follow', fakeFilter())
const httpSignature = {
algorithm: HTTP_SIGNATURE.ALGORITHM,
authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
keyId: by.url,
key: by.privateKey,
headers: HTTP_SIGNATURE.HEADERS_TO_SIGN_WITH_PAYLOAD
@@ -97,8 +95,6 @@ describe('Test ActivityPub security', function () {
const keys = readJsonSync(buildAbsoluteFixturePath('./ap-json/peertube/keys.json'))
const invalidKeys = readJsonSync(buildAbsoluteFixturePath('./ap-json/peertube/invalid-keys.json'))
const baseHttpSignature = () => ({
algorithm: HTTP_SIGNATURE.ALGORITHM,
authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
keyId: 'acct:peertube@' + servers[1].host,
key: keys.privateKey,
headers: HTTP_SIGNATURE.HEADERS_TO_SIGN_WITH_PAYLOAD
@@ -124,7 +120,6 @@ describe('Test ActivityPub security', function () {
})
describe('When checking HTTP signature', function () {
it('Should fail with an invalid digest', async function () {
const body = await activityPubContextify(getAnnounceWithoutContext(servers[1]), 'Announce', fakeFilter())
const headers = {
@@ -29,9 +29,7 @@ function fakeExpressReq (body: any) {
}
describe('Test activity pub helpers', function () {
describe('When checking the Linked Signature', function () {
it('Should fail with an invalid Mastodon signature', async function () {
const body = readJsonSync(buildAbsoluteFixturePath('./ap-json/mastodon/create-bad-signature.json'))
const publicKey = readJsonSync(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
@@ -115,7 +113,7 @@ describe('Test activity pub helpers', function () {
const publicKey = readJsonSync(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
const actor = { publicKey }
const verified = isHTTPSignatureVerified(parsed, actor as any)
const verified = await isHTTPSignatureVerified(parsed, actor as any)
expect(verified).to.be.false
})
@@ -133,7 +131,7 @@ describe('Test activity pub helpers', function () {
const publicKey = readJsonSync(buildAbsoluteFixturePath('./ap-json/mastodon/bad-public-key.json')).publicKey
const actor = { publicKey }
const verified = isHTTPSignatureVerified(parsed, actor as any)
const verified = await isHTTPSignatureVerified(parsed, actor as any)
expect(verified).to.be.false
})
@@ -190,11 +188,9 @@ describe('Test activity pub helpers', function () {
const publicKey = readJsonSync(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
const actor = { publicKey }
const verified = isHTTPSignatureVerified(parsed, actor as any)
const verified = await isHTTPSignatureVerified(parsed, actor as any)
expect(verified).to.be.true
})
})
})
+35 -121
View File
@@ -38,6 +38,9 @@ importers:
'@jimp/plugin-color':
specifier: ^1.6.0
version: 1.6.0
'@misskey-dev/node-http-message-signatures':
specifier: ^0.0.10
version: 0.0.10
'@node-oauth/oauth2-server':
specifier: ^5.2.1
version: 5.2.1
@@ -92,9 +95,6 @@ importers:
'@peertube/feed':
specifier: ^5.4.1
version: 5.4.1
'@peertube/http-signature':
specifier: ^1.7.0
version: 1.7.0
'@peertube/peertube-core-utils':
specifier: workspace:*
version: link:packages/core-utils
@@ -2547,6 +2547,11 @@ packages:
resolution: {integrity: sha512-QYeYGz6uJaH41ZVyNoI2Lt2NyfcpKwpDIBMx3psaE1NBJn8P+jk1m0EIjphfYvnRMnl/QyBpn98FfcTUjTkuBw==}
engines: {node: '>=14'}
'@lapo/asn1js@2.1.1':
resolution: {integrity: sha512-a4wOBae3D8EfOEcGjLyQIFIgNh+5I80a804jM7oMnH8WcMKdOZoa1xGc92wDo4k6EzKovkNwaUbnmkOr5CuAWQ==}
engines: {node: '>=14.6.0'}
hasBin: true
'@listr2/prompt-adapter-inquirer@3.0.1':
resolution: {integrity: sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==}
engines: {node: '>=20.0.0'}
@@ -2607,6 +2612,10 @@ packages:
'@minimistjs/subarg@1.0.0':
resolution: {integrity: sha512-Q/ONBiM2zNeYUy0mVSO44mWWKYM3UHuEK43PKIOzJCbvUnPoMH1K+gk3cf1kgnCVJFlWmddahQQCmrmBGlk9jQ==}
'@misskey-dev/node-http-message-signatures@0.0.10':
resolution: {integrity: sha512-HiAuc//tOU077KFUJhHYLAPWku9enTpOFIqQiK6l2i2mIizRvv7HhV7Y+yuav5quDOAz+WZGK/i5C9OR5fkKIg==}
engines: {node: '>=18.4.0'}
'@modelcontextprotocol/sdk@1.17.3':
resolution: {integrity: sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==}
engines: {node: '>=18'}
@@ -3062,10 +3071,6 @@ packages:
resolution: {integrity: sha512-WgqTn5NuejZ+HSon8JzwTapDu3SzjR1FqajpbvpX/g20z8Bd8i4mO0jmrC6Zk4XVK2LrRN2Bx0jdAhBmtgLa/Q==}
engines: {node: '>=0.4.0'}
'@peertube/http-signature@1.7.0':
resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==}
engines: {node: '>=0.10'}
'@peertube/maildev@1.2.0':
resolution: {integrity: sha512-VGog0A2gk0P8UnP0ZjCoYQumELiqqQY5i+gt18avTC7NJNJLUxMRMI045NAVSDFVbqt2EJJPsbZf3LFjUWRtmw==}
engines: {node: '>=10.0.0'}
@@ -3437,6 +3442,7 @@ packages:
'@smithy/core@3.18.3':
resolution: {integrity: sha512-qqpNskkbHOSfrbFbjhYj5o8VMXO26fvN1K/+HbCzUNlTuxgNcPRouUDNm+7D6CkN244WG7aK533Ne18UtJEgAA==}
engines: {node: '>=18.0.0'}
deprecated: Please upgrade your lockfile to use the latest 3.x version of @smithy/core for various fixes, see https://github.com/smithy-lang/smithy-typescript/blob/main/packages/core/CHANGELOG.md
'@smithy/credential-provider-imds@4.2.5':
resolution: {integrity: sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==}
@@ -4401,16 +4407,9 @@ packages:
asn1.js@4.10.1:
resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==}
asn1@0.2.6:
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
assert-never@1.4.0:
resolution: {integrity: sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==}
assert-plus@1.0.0:
resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
engines: {node: '>=0.8'}
assert@2.1.0:
resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
@@ -4583,9 +4582,6 @@ packages:
resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
engines: {node: '>=10.0.0'}
bcrypt-pbkdf@1.0.2:
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
bcrypt@6.0.0:
resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==}
engines: {node: '>= 18'}
@@ -5184,9 +5180,6 @@ packages:
core-js@3.46.0:
resolution: {integrity: sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==}
core-util-is@1.0.2:
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -5314,10 +5307,6 @@ packages:
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
engines: {node: '>=0.12'}
dashdash@1.14.1:
resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
engines: {node: '>=0.10'}
data-uri-to-buffer@4.0.1:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
@@ -5605,9 +5594,6 @@ packages:
easy-table@1.2.0:
resolution: {integrity: sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==}
ecc-jsbn@0.1.2:
resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
ecdsa-sig-formatter@1.0.11:
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
@@ -6059,10 +6045,6 @@ packages:
engines: {node: '>= 10.17.0'}
hasBin: true
extsprintf@1.3.0:
resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
engines: {'0': node >=0.6.0}
eyes@0.1.8:
resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==}
engines: {node: '> 0.1.90'}
@@ -6416,9 +6398,6 @@ packages:
resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==}
engines: {node: '>= 14'}
getpass@0.1.7:
resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
gifwrap@0.10.1:
resolution: {integrity: sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==}
@@ -7213,9 +7192,6 @@ packages:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
jsbn@0.1.1:
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
jschannel@1.0.2:
resolution: {integrity: sha512-y3cXMp8IWckhlCOvDxg+TcuNSHYA6PLm9tVuYHdfMhjtFgTrinv6gcoOdeg9RG4XA8UzmgFsM92EpUKJ8qmcpw==}
@@ -7253,9 +7229,6 @@ packages:
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
json-schema@0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
@@ -7292,10 +7265,6 @@ packages:
resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==}
engines: {node: '>=12', npm: '>=6'}
jsprim@1.4.2:
resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
engines: {node: '>=0.6.0'}
jstransformer@1.0.0:
resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
@@ -9121,6 +9090,9 @@ packages:
resolution: {integrity: sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==}
engines: {node: '>= 0.4.0'}
rfc4648@1.5.4:
resolution: {integrity: sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==}
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
@@ -9668,11 +9640,6 @@ packages:
resolution: {integrity: sha512-QHy2syDTGUzQiDtKwqSunVdh0H5dhtVt9bh/Z+yTcminD69UKk3RFVhUtBjoCh/W5OYX36Igwv5qy2JZPISwgQ==}
hasBin: true
sshpk@1.18.0:
resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==}
engines: {node: '>=0.10.0'}
hasBin: true
ssri@12.0.0:
resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -9829,6 +9796,10 @@ packages:
resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==}
engines: {node: '>=10'}
structured-headers@1.0.1:
resolution: {integrity: sha512-QYBxdBtA4Tl5rFPuqmbmdrS9kbtren74RTJTcs0VSQNVV5iRhJD4QlYTLD0+81SBwUQctjEQzjTRI3WG4DzICA==}
engines: {node: '>= 14', npm: '>=6'}
style-search@0.1.0:
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
@@ -10162,9 +10133,6 @@ packages:
resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==}
engines: {node: '>= 0.8.0'}
tweetnacl@0.14.5:
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -10424,10 +10392,6 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
verror@1.10.0:
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
engines: {'0': node >=0.6.0}
video.js@8.23.4:
resolution: {integrity: sha512-qI0VTlYmKzEqRsz1Nppdfcaww4RSxZAq77z2oNSl3cNg2h6do5C8Ffl0KqWQ1OpD8desWXsCrde7tKJ9gGTEyQ==}
@@ -12860,6 +12824,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@lapo/asn1js@2.1.1': {}
'@listr2/prompt-adapter-inquirer@3.0.1(@inquirer/prompts@7.8.2(@types/node@20.19.25))(@types/node@20.19.25)(listr2@9.0.1)':
dependencies:
'@inquirer/prompts': 7.8.2(@types/node@20.19.25)
@@ -12914,6 +12880,12 @@ snapshots:
dependencies:
minimist: 1.2.8
'@misskey-dev/node-http-message-signatures@0.0.10':
dependencies:
'@lapo/asn1js': 2.1.1
rfc4648: 1.5.4
structured-headers: 1.0.1
'@modelcontextprotocol/sdk@1.17.3':
dependencies:
ajv: 6.12.6
@@ -13370,12 +13342,6 @@ snapshots:
dependencies:
xml-js: 1.6.11
'@peertube/http-signature@1.7.0':
dependencies:
assert-plus: 1.0.0
jsprim: 1.4.2
sshpk: 1.18.0
'@peertube/maildev@1.2.0':
dependencies:
async: 3.2.6
@@ -15110,14 +15076,8 @@ snapshots:
inherits: 2.0.4
minimalistic-assert: 1.0.1
asn1@0.2.6:
dependencies:
safer-buffer: 2.1.2
assert-never@1.4.0: {}
assert-plus@1.0.0: {}
assert@2.1.0:
dependencies:
call-bind: 1.0.8
@@ -15285,10 +15245,6 @@ snapshots:
basic-ftp@5.0.5: {}
bcrypt-pbkdf@1.0.2:
dependencies:
tweetnacl: 0.14.5
bcrypt@6.0.0:
dependencies:
node-addon-api: 8.5.0
@@ -15701,7 +15657,7 @@ snapshots:
centra@2.7.0:
dependencies:
follow-redirects: 1.15.11(debug@4.4.3)
follow-redirects: 1.15.11
transitivePeerDependencies:
- debug
@@ -16046,8 +16002,6 @@ snapshots:
core-js@3.46.0: {}
core-util-is@1.0.2: {}
core-util-is@1.0.3: {}
cors@2.8.5:
@@ -16228,10 +16182,6 @@ snapshots:
es5-ext: 0.10.64
type: 2.7.3
dashdash@1.14.1:
dependencies:
assert-plus: 1.0.0
data-uri-to-buffer@4.0.1: {}
data-uri-to-buffer@6.0.2: {}
@@ -16509,11 +16459,6 @@ snapshots:
optionalDependencies:
wcwidth: 1.0.1
ecc-jsbn@0.1.2:
dependencies:
jsbn: 0.1.1
safer-buffer: 2.1.2
ecdsa-sig-formatter@1.0.11:
dependencies:
safe-buffer: 5.2.1
@@ -17294,8 +17239,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
extsprintf@1.3.0: {}
eyes@0.1.8: {}
fast-copy@3.0.2: {}
@@ -17476,6 +17419,8 @@ snapshots:
fn.name@1.1.0: {}
follow-redirects@1.15.11: {}
follow-redirects@1.15.11(debug@4.4.3):
optionalDependencies:
debug: 4.4.3(supports-color@8.1.1)
@@ -17708,10 +17653,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
getpass@0.1.7:
dependencies:
assert-plus: 1.0.0
gifwrap@0.10.1:
dependencies:
image-q: 4.0.0
@@ -18602,8 +18543,6 @@ snapshots:
dependencies:
argparse: 2.0.1
jsbn@0.1.1: {}
jschannel@1.0.2: {}
jsdom@24.1.3(bufferutil@4.0.9)(utf-8-validate@6.0.5):
@@ -18648,8 +18587,6 @@ snapshots:
json-schema-traverse@1.0.0: {}
json-schema@0.4.0: {}
json-stable-stringify-without-jsonify@1.0.1: {}
json5@1.0.2:
@@ -18696,13 +18633,6 @@ snapshots:
ms: 2.1.3
semver: 7.7.3
jsprim@1.4.2:
dependencies:
assert-plus: 1.0.0
extsprintf: 1.3.0
json-schema: 0.4.0
verror: 1.10.0
jstransformer@1.0.0:
dependencies:
is-promise: 2.2.2
@@ -20826,6 +20756,8 @@ snapshots:
revalidator@0.1.8: {}
rfc4648@1.5.4: {}
rfdc@1.4.1: {}
rgb2hex@0.2.5: {}
@@ -21488,18 +21420,6 @@ snapshots:
through2: 0.6.5
to-utf-8: 1.3.0
sshpk@1.18.0:
dependencies:
asn1: 0.2.6
assert-plus: 1.0.0
bcrypt-pbkdf: 1.0.2
dashdash: 1.14.1
ecc-jsbn: 0.1.2
getpass: 0.1.7
jsbn: 0.1.1
safer-buffer: 2.1.2
tweetnacl: 0.14.5
ssri@12.0.0:
dependencies:
minipass: 7.1.2
@@ -21674,6 +21594,8 @@ snapshots:
'@tokenizer/token': 0.3.0
peek-readable: 4.1.0
structured-headers@1.0.1: {}
style-search@0.1.0: {}
stylelint-config-sass-guidelines@12.1.0(postcss@8.5.6)(stylelint@16.25.0(typescript@5.9.3)):
@@ -22111,8 +22033,6 @@ snapshots:
tv4@1.3.0: {}
tweetnacl@0.14.5: {}
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
@@ -22371,12 +22291,6 @@ snapshots:
vary@1.1.2: {}
verror@1.10.0:
dependencies:
assert-plus: 1.0.0
core-util-is: 1.0.2
extsprintf: 1.3.0
video.js@8.23.4(patch_hash=66459642658d85da52b45ff0472242e9daade1ff3dd765974103db72a7c55377):
dependencies:
'@babel/runtime': 7.28.4
+1 -1
View File
@@ -230,7 +230,7 @@ function generateRSAKeyPairPromise (size: number) {
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs1',
type: 'pkcs8',
format: 'pem'
}
}
+33 -12
View File
@@ -1,8 +1,8 @@
import httpSignature from '@peertube/http-signature'
import { ParsedDraftSignature, parseRequestSignature, verifyDraftSignature } from '@misskey-dev/node-http-message-signatures'
import { sha256 } from '@peertube/peertube-node-utils'
import { createCipheriv, createDecipheriv } from 'crypto'
import { Request } from 'express'
import { BCRYPT_SALT_SIZE, ENCRYPTION, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers/constants.js'
import { BCRYPT_SALT_SIZE, ENCRYPTION, PRIVATE_RSA_KEY_SIZE } from '../initializers/constants.js'
import { MActor } from '../types/models/index.js'
import { generateRSAKeyPairPromise, randomBytesPromise, scryptPromise } from './core-utils.js'
import { logger } from './logger.js'
@@ -42,25 +42,46 @@ async function cryptPassword (password: string) {
// ---------------------------------------------------------------------------
function isHTTPSignatureDigestValid (rawBody: Buffer, req: Request): boolean {
if (req.headers[HTTP_SIGNATURE.HEADER_NAME] && req.headers['digest']) {
if (req.headers['signature'] && req.headers['digest']) {
return buildDigest(rawBody.toString()) === req.headers['digest']
}
return true
}
function isHTTPSignatureVerified (httpSignatureParsed: any, actor: MActor): boolean {
return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true
async function isHTTPSignatureVerified (httpSignatureParsed: ParsedDraftSignature, actor: MActor): Promise<boolean> {
const result = await verifyDraftSignature(
httpSignatureParsed.value,
actor.publicKey,
msg => logger.debug('Error in verify draft signature: ' + msg)
)
return result === true
}
function parseHTTPSignature (req: Request, clockSkew?: number) {
function parseHTTPSignature (req: Request, clockSkewSeconds?: number): ParsedDraftSignature {
const requiredHeaders = req.method === 'POST'
? [ '(request-target)', 'host', 'digest' ]
: [ '(request-target)', 'host' ]
const parsed = httpSignature.parse(req, { clockSkew, headers: requiredHeaders })
const clockSkew = clockSkewSeconds
? clockSkewSeconds * 1000
: undefined
const parsedHeaders = parsed.params.headers
const parsed = parseRequestSignature(req, {
requiredComponents: {
draft: requiredHeaders
},
clockSkew: {
delay: clockSkew
}
})
if (parsed.version !== 'draft') {
throw new Error(`Only draft version of HTTP signature is supported`)
}
const parsedHeaders = parsed.value.params.headers
if (!parsedHeaders.includes('date') && !parsedHeaders.includes('(created)')) {
throw new Error(`date or (created) must be included in signature`)
}
@@ -107,13 +128,13 @@ async function decrypt (encryptedArg: string, secret: string) {
// ---------------------------------------------------------------------------
export {
isHTTPSignatureDigestValid,
parseHTTPSignature,
isHTTPSignatureVerified,
buildDigest,
comparePassword,
createPrivateAndPublicKeys,
cryptPassword,
decrypt,
encrypt,
decrypt
isHTTPSignatureDigestValid,
isHTTPSignatureVerified,
parseHTTPSignature
}
+16 -19
View File
@@ -1,4 +1,4 @@
import httpSignature from '@peertube/http-signature'
import { signAsDraftToRequest } from '@misskey-dev/node-http-message-signatures'
import { CONFIG } from '@server/initializers/config.js'
import { createWriteStream } from 'fs'
import { remove } from 'fs-extra/esm'
@@ -38,8 +38,6 @@ export type PeerTubeRequestOptions = {
bodyKBLimit?: number // 1MB
httpSignature?: {
algorithm: string
authorizationHeaderName: string
keyId: string
key: string
headers: string[]
@@ -91,8 +89,8 @@ export const unsafeSSRFGot = got.extend({
headers['host'] = buildUrl(options.url).host
},
options => {
const httpSignatureOptions = options.context?.httpSignature
async options => {
const httpSignatureOptions = options.context?.httpSignature as PeerTubeRequestOptions['httpSignature']
if (httpSignatureOptions) {
const method = options.method ?? 'GET'
@@ -102,21 +100,20 @@ export const unsafeSSRFGot = got.extend({
throw new Error(`Cannot sign request without method (${method}) or path (${path}) ${options}`)
}
httpSignature.signRequest({
getHeader: function (header: string) {
const value = options.headers[header.toLowerCase()]
if (!value) logger.warn('Unknown header requested by http-signature.', { headers: options.headers, header })
return value
},
setHeader: function (header: string, value: string) {
options.headers[header] = value
},
const request = {
headers: options.headers,
method,
path
}, httpSignatureOptions)
url: path
}
await signAsDraftToRequest(
request,
{
keyId: httpSignatureOptions.keyId,
privateKeyPem: httpSignatureOptions.key
},
httpSignatureOptions.headers
)
}
}
],
+1 -3
View File
@@ -58,7 +58,7 @@ import { CONFIG, registerConfigChangedHandler } from './config.js'
// ---------------------------------------------------------------------------
export const LAST_MIGRATION_VERSION = 970
export const LAST_MIGRATION_VERSION = 975
// ---------------------------------------------------------------------------
@@ -858,8 +858,6 @@ export const ACTIVITY_PUB_ACTOR_TYPES: { [id: string]: ActivityPubActorType } =
}
export const HTTP_SIGNATURE = {
HEADER_NAME: 'signature',
ALGORITHM: 'rsa-sha256',
HEADERS_TO_SIGN_WITH_PAYLOAD: [ '(request-target)', 'host', 'date', 'digest' ],
HEADERS_TO_SIGN_WITHOUT_PAYLOAD: [ '(request-target)', 'host', 'date' ],
CLOCK_SKEW_SECONDS: 1800
@@ -0,0 +1,45 @@
import { createPrivateKey } from 'crypto'
import * as Sequelize from 'sequelize'
async function up (utils: {
transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const rows = await utils.sequelize.query<{ id: number, privateKey: string }>(
'SELECT "id", "privateKey" FROM "actor" WHERE "serverId" IS NULL',
{ type: Sequelize.QueryTypes.SELECT as Sequelize.QueryTypes.SELECT, transaction: utils.transaction }
)
for (const { id, privateKey } of rows) {
const newPrivateKey = toPKCS8(privateKey)
await utils.sequelize.query('UPDATE "actor" SET "privateKey" = :newPrivateKey WHERE "id" = :id', {
replacements: { newPrivateKey, id },
transaction: utils.transaction
})
}
}
function down (options) {
throw new Error('Not implemented.')
}
export {
down,
up
}
// ---------------------------------------------------------------------------
function toPKCS8 (privateKeyPEM: string) {
const keyObject = createPrivateKey({
key: privateKeyPEM,
format: 'pem'
})
return keyObject.export({
type: 'pkcs8',
format: 'pem'
}).toString()
}
-2
View File
@@ -51,8 +51,6 @@ export async function buildSignedRequestOptions (options: {
: await getServerActor() // We need to sign the request, so use the server
return {
algorithm: HTTP_SIGNATURE.ALGORITHM,
authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
keyId: ActorModel.getPublicKeyUrl(actor.url),
key: actor.privateKey,
headers: options.hasPayload
+12 -9
View File
@@ -1,10 +1,11 @@
import { ParsedDraftSignature } from '@misskey-dev/node-http-message-signatures'
import { ActivityDelete, ActivityPubSignature, HttpStatusCode } from '@peertube/peertube-models'
import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor.js'
import { isHTTPSignatureVerified, parseHTTPSignature } from '@server/helpers/peertube-crypto.js'
import { getAPId } from '@server/lib/activitypub/activity.js'
import { wrapWithSpanAndContext } from '@server/lib/opentelemetry/tracing.js'
import { NextFunction, Request, Response } from 'express'
import { logger } from '../helpers/logger.js'
import { isHTTPSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto.js'
import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants.js'
import { getOrCreateAPActor, loadActorUrlOrGetFromWebfinger } from '../lib/activitypub/actors/index.js'
@@ -58,10 +59,10 @@ export function executeIfActivityPub (req: Request, res: Response, next: NextFun
async function checkHttpSignature (req: Request, res: Response) {
return wrapWithSpanAndContext('peertube.activitypub.checkHTTPSignature', async () => {
// Compatibility with http-signature < v1.3
const sig = req.headers[HTTP_SIGNATURE.HEADER_NAME] as string
if (sig && sig.startsWith('Signature ') === true) req.headers[HTTP_SIGNATURE.HEADER_NAME] = sig.replace(/^Signature /, '')
const sig = req.headers['signature'] as string
if (sig && sig.startsWith('Signature ') === true) req.headers['signature'] = sig.replace(/^Signature /, '')
let parsed: any
let parsed: ParsedDraftSignature
try {
parsed = parseHTTPSignature(req, HTTP_SIGNATURE.CLOCK_SKEW_SECONDS)
@@ -70,16 +71,17 @@ async function checkHttpSignature (req: Request, res: Response) {
res.fail({
status: HttpStatusCode.FORBIDDEN_403,
message: err.message
message: req.t('Cannot parse HTTP signature')
})
return false
}
const keyId = parsed.keyId
const keyId = parsed.value?.keyId
if (!keyId) {
res.fail({
status: HttpStatusCode.FORBIDDEN_403,
message: 'Invalid key ID',
message: req.t('Invalid key ID'),
data: {
keyId
}
@@ -96,13 +98,14 @@ async function checkHttpSignature (req: Request, res: Response) {
const actor = await getOrCreateAPActor(actorUrl)
const verified = isHTTPSignatureVerified(parsed, actor)
const verified = await isHTTPSignatureVerified(parsed, actor)
if (verified !== true) {
logger.warn('Signature from %s is invalid', actorUrl, { parsed })
res.fail({
status: HttpStatusCode.FORBIDDEN_403,
message: 'Invalid signature',
message: req.t('Invalid signature'),
data: {
actorUrl
}