浏览代码

Fix weird bug where CPU jumps and stays to 100%

Seems related to lazy import of custom-jsonld-signature
So we refactored jsonld function calls a little bit
Chocobozzz 6 月之前
父节点
当前提交
b017d4d02f

+ 2 - 1
server/core/helpers/activity-pub-utils.ts

@@ -1,6 +1,7 @@
 import { ContextType } from '@peertube/peertube-models'
 import { ACTIVITY_PUB } from '@server/initializers/constants.js'
-import { buildDigest, signJsonLDObject } from './peertube-crypto.js'
+import { buildDigest } from './peertube-crypto.js'
+import type { signJsonLDObject } from './peertube-jsonld.js'
 
 export type ContextFilter = <T> (arg: T) => Promise<T>
 

+ 1 - 102
server/core/helpers/peertube-crypto.ts

@@ -1,13 +1,11 @@
 import httpSignature from '@peertube/http-signature'
 import { sha256 } from '@peertube/peertube-node-utils'
-import { createCipheriv, createDecipheriv, createSign, createVerify } from 'crypto'
+import { createCipheriv, createDecipheriv } from 'crypto'
 import { Request } from 'express'
-import cloneDeep from 'lodash-es/cloneDeep.js'
 import { BCRYPT_SALT_SIZE, ENCRYPTION, HTTP_SIGNATURE, 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'
-import { assertIsInWorkerThread } from './threads.js'
 
 function createPrivateAndPublicKeys () {
   logger.info('Generating a RSA key...')
@@ -66,66 +64,6 @@ function parseHTTPSignature (req: Request, clockSkew?: number) {
   return parsed
 }
 
-// ---------------------------------------------------------------------------
-// JSONLD
-// ---------------------------------------------------------------------------
-
-function isJsonLDSignatureVerified (fromActor: MActor, signedDocument: any): Promise<boolean> {
-  if (signedDocument.signature.type === 'RsaSignature2017') {
-    return isJsonLDRSA2017Verified(fromActor, signedDocument)
-  }
-
-  logger.warn('Unknown JSON LD signature %s.', signedDocument.signature.type, signedDocument)
-
-  return Promise.resolve(false)
-}
-
-// Backward compatibility with "other" implementations
-async function isJsonLDRSA2017Verified (fromActor: MActor, signedDocument: any) {
-  const [ documentHash, optionsHash ] = await Promise.all([
-    createDocWithoutSignatureHash(signedDocument),
-    createSignatureHash(signedDocument.signature)
-  ])
-
-  const toVerify = optionsHash + documentHash
-
-  const verify = createVerify('RSA-SHA256')
-  verify.update(toVerify, 'utf8')
-
-  return verify.verify(fromActor.publicKey, signedDocument.signature.signatureValue, 'base64')
-}
-
-async function signJsonLDObject <T> (options: {
-  byActor: { url: string, privateKey: string }
-  data: T
-  disableWorkerThreadAssertion?: boolean
-}) {
-  const { byActor, data, disableWorkerThreadAssertion = false } = options
-
-  if (!disableWorkerThreadAssertion) assertIsInWorkerThread()
-
-  const signature = {
-    type: 'RsaSignature2017',
-    creator: byActor.url,
-    created: new Date().toISOString()
-  }
-
-  const [ documentHash, optionsHash ] = await Promise.all([
-    createDocWithoutSignatureHash(data),
-    createSignatureHash(signature)
-  ])
-
-  const toSign = optionsHash + documentHash
-
-  const sign = createSign('RSA-SHA256')
-  sign.update(toSign, 'utf8')
-
-  const signatureValue = sign.sign(byActor.privateKey, 'base64')
-  Object.assign(signature, { signatureValue })
-
-  return Object.assign(data, { signature })
-}
-
 // ---------------------------------------------------------------------------
 
 function buildDigest (body: any) {
@@ -169,49 +107,10 @@ export {
   parseHTTPSignature,
   isHTTPSignatureVerified,
   buildDigest,
-  isJsonLDSignatureVerified,
   comparePassword,
   createPrivateAndPublicKeys,
   cryptPassword,
-  signJsonLDObject,
 
   encrypt,
   decrypt
 }
-
-// ---------------------------------------------------------------------------
-
-async function hashObject (obj: any): Promise<any> {
-  const { jsonld } = await import('./custom-jsonld-signature.js')
-
-  const res = await (jsonld as any).promises.normalize(obj, {
-    safe: false,
-    algorithm: 'URDNA2015',
-    format: 'application/n-quads'
-  })
-
-  return sha256(res)
-}
-
-function createSignatureHash (signature: any) {
-  const signatureCopy = cloneDeep(signature)
-  Object.assign(signatureCopy, {
-    '@context': [
-      'https://w3id.org/security/v1',
-      { RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' }
-    ]
-  })
-
-  delete signatureCopy.type
-  delete signatureCopy.id
-  delete signatureCopy.signatureValue
-
-  return hashObject(signatureCopy)
-}
-
-function createDocWithoutSignatureHash (doc: any) {
-  const docWithoutSignature = cloneDeep(doc)
-  delete docWithoutSignature.signature
-
-  return hashObject(docWithoutSignature)
-}

+ 100 - 0
server/core/helpers/peertube-jsonld.ts

@@ -0,0 +1,100 @@
+import { sha256 } from '@peertube/peertube-node-utils'
+import { createSign, createVerify } from 'crypto'
+import cloneDeep from 'lodash-es/cloneDeep.js'
+import { MActor } from '../types/models/index.js'
+import { logger } from './logger.js'
+import { assertIsInWorkerThread } from './threads.js'
+import { jsonld } from './custom-jsonld-signature.js'
+
+export function isJsonLDSignatureVerified (fromActor: MActor, signedDocument: any): Promise<boolean> {
+  if (signedDocument.signature.type === 'RsaSignature2017') {
+    return isJsonLDRSA2017Verified(fromActor, signedDocument)
+  }
+
+  logger.warn('Unknown JSON LD signature %s.', signedDocument.signature.type, signedDocument)
+
+  return Promise.resolve(false)
+}
+
+// Backward compatibility with "other" implementations
+export async function isJsonLDRSA2017Verified (fromActor: MActor, signedDocument: any) {
+  const [ documentHash, optionsHash ] = await Promise.all([
+    createDocWithoutSignatureHash(signedDocument),
+    createSignatureHash(signedDocument.signature)
+  ])
+
+  const toVerify = optionsHash + documentHash
+
+  const verify = createVerify('RSA-SHA256')
+  verify.update(toVerify, 'utf8')
+
+  return verify.verify(fromActor.publicKey, signedDocument.signature.signatureValue, 'base64')
+}
+
+export async function signJsonLDObject <T> (options: {
+  byActor: { url: string, privateKey: string }
+  data: T
+  disableWorkerThreadAssertion?: boolean
+}) {
+  const { byActor, data, disableWorkerThreadAssertion = false } = options
+
+  if (!disableWorkerThreadAssertion) assertIsInWorkerThread()
+
+  const signature = {
+    type: 'RsaSignature2017',
+    creator: byActor.url,
+    created: new Date().toISOString()
+  }
+
+  const [ documentHash, optionsHash ] = await Promise.all([
+    createDocWithoutSignatureHash(data),
+    createSignatureHash(signature)
+  ])
+
+  const toSign = optionsHash + documentHash
+
+  const sign = createSign('RSA-SHA256')
+  sign.update(toSign, 'utf8')
+
+  const signatureValue = sign.sign(byActor.privateKey, 'base64')
+  Object.assign(signature, { signatureValue })
+
+  return Object.assign(data, { signature })
+}
+
+// ---------------------------------------------------------------------------
+// Private
+// ---------------------------------------------------------------------------
+
+async function hashObject (obj: any): Promise<any> {
+  const res = await (jsonld as any).promises.normalize(obj, {
+    safe: false,
+    algorithm: 'URDNA2015',
+    format: 'application/n-quads'
+  })
+
+  return sha256(res)
+}
+
+function createSignatureHash (signature: any) {
+  const signatureCopy = cloneDeep(signature)
+  Object.assign(signatureCopy, {
+    '@context': [
+      'https://w3id.org/security/v1',
+      { RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' }
+    ]
+  })
+
+  delete signatureCopy.type
+  delete signatureCopy.id
+  delete signatureCopy.signatureValue
+
+  return hashObject(signatureCopy)
+}
+
+function createDocWithoutSignatureHash (doc: any) {
+  const docWithoutSignature = cloneDeep(doc)
+  delete docWithoutSignature.signature
+
+  return hashObject(docWithoutSignature)
+}

+ 1 - 1
server/core/lib/worker/workers/sign-json-ld-object.ts

@@ -1,3 +1,3 @@
-import { signJsonLDObject } from '@server/helpers/peertube-crypto.js'
+import { signJsonLDObject } from '@server/helpers/peertube-jsonld.js'
 
 export default signJsonLDObject

+ 4 - 1
server/core/middlewares/activitypub.ts

@@ -4,7 +4,7 @@ import { getAPId } from '@server/lib/activitypub/activity.js'
 import { wrapWithSpanAndContext } from '@server/lib/opentelemetry/tracing.js'
 import { ActivityDelete, ActivityPubSignature, HttpStatusCode } from '@peertube/peertube-models'
 import { logger } from '../helpers/logger.js'
-import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto.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'
 
@@ -122,6 +122,9 @@ async function checkHttpSignature (req: Request, res: Response) {
 }
 
 async function checkJsonLDSignature (req: Request, res: Response) {
+  // Lazy load the module as it's quite big with json.ld dependency
+  const { isJsonLDSignatureVerified } = await import('../helpers/peertube-jsonld.js')
+
   return wrapWithSpanAndContext('peertube.activitypub.JSONLDSignature', async () => {
     const signatureObject: ActivityPubSignature = req.body.signature