aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-08-11 14:10:18 +0200
committerChocobozzz <me@florianbigard.com>2022-08-11 14:10:18 +0200
commit2a95b88477a547c319108c0bab8692624df6804c (patch)
treef464c7bb0a774b8d4b672edf023b9a8126787c91
parentab08ab4e284ad145de64ff9e1c9cf8149f701e29 (diff)
downloadPeerTube-2a95b88477a547c319108c0bab8692624df6804c.tar.gz
PeerTube-2a95b88477a547c319108c0bab8692624df6804c.tar.zst
PeerTube-2a95b88477a547c319108c0bab8692624df6804c.zip
Add spans for AP signature checkers
-rw-r--r--server/lib/opentelemetry/tracing.ts17
-rw-r--r--server/middlewares/activitypub.ts147
2 files changed, 90 insertions, 74 deletions
diff --git a/server/lib/opentelemetry/tracing.ts b/server/lib/opentelemetry/tracing.ts
index 252a3b664..b1c3bd173 100644
--- a/server/lib/opentelemetry/tracing.ts
+++ b/server/lib/opentelemetry/tracing.ts
@@ -1,5 +1,5 @@
1import { SequelizeInstrumentation } from 'opentelemetry-instrumentation-sequelize' 1import { SequelizeInstrumentation } from 'opentelemetry-instrumentation-sequelize'
2import { diag, DiagLogLevel, trace } from '@opentelemetry/api' 2import { context, diag, DiagLogLevel, trace } from '@opentelemetry/api'
3import { JaegerExporter } from '@opentelemetry/exporter-jaeger' 3import { JaegerExporter } from '@opentelemetry/exporter-jaeger'
4import { registerInstrumentations } from '@opentelemetry/instrumentation' 4import { registerInstrumentations } from '@opentelemetry/instrumentation'
5import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns' 5import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns'
@@ -15,6 +15,8 @@ import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
15import { logger } from '@server/helpers/logger' 15import { logger } from '@server/helpers/logger'
16import { CONFIG } from '@server/initializers/config' 16import { CONFIG } from '@server/initializers/config'
17 17
18const tracer = trace.getTracer('peertube')
19
18function registerOpentelemetryTracing () { 20function registerOpentelemetryTracing () {
19 if (CONFIG.OPEN_TELEMETRY.TRACING.ENABLED !== true) return 21 if (CONFIG.OPEN_TELEMETRY.TRACING.ENABLED !== true) return
20 22
@@ -75,9 +77,18 @@ function registerOpentelemetryTracing () {
75 tracerProvider.register() 77 tracerProvider.register()
76} 78}
77 79
78const tracer = trace.getTracer('peertube') 80async function wrapWithSpanAndContext <T> (spanName: string, cb: () => Promise<T>) {
81 const span = tracer.startSpan(spanName)
82 const activeContext = trace.setSpan(context.active(), span)
83
84 const result = await context.with(activeContext, () => cb())
85 span.end()
86
87 return result
88}
79 89
80export { 90export {
81 registerOpentelemetryTracing, 91 registerOpentelemetryTracing,
82 tracer 92 tracer,
93 wrapWithSpanAndContext
83} 94}
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts
index 2a2d86a24..0064a4760 100644
--- a/server/middlewares/activitypub.ts
+++ b/server/middlewares/activitypub.ts
@@ -1,6 +1,7 @@
1import { NextFunction, Request, Response } from 'express' 1import { NextFunction, Request, Response } from 'express'
2import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' 2import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor'
3import { getAPId } from '@server/lib/activitypub/activity' 3import { getAPId } from '@server/lib/activitypub/activity'
4import { wrapWithSpanAndContext } from '@server/lib/opentelemetry/tracing'
4import { ActivityDelete, ActivityPubSignature, HttpStatusCode } from '@shared/models' 5import { ActivityDelete, ActivityPubSignature, HttpStatusCode } from '@shared/models'
5import { logger } from '../helpers/logger' 6import { logger } from '../helpers/logger'
6import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' 7import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto'
@@ -61,91 +62,95 @@ export {
61// --------------------------------------------------------------------------- 62// ---------------------------------------------------------------------------
62 63
63async function checkHttpSignature (req: Request, res: Response) { 64async function checkHttpSignature (req: Request, res: Response) {
64 // FIXME: compatibility with http-signature < v1.3 65 return wrapWithSpanAndContext('peertube.activitypub.checkHTTPSignature', async () => {
65 const sig = req.headers[HTTP_SIGNATURE.HEADER_NAME] as string 66 // FIXME: compatibility with http-signature < v1.3
66 if (sig && sig.startsWith('Signature ') === true) req.headers[HTTP_SIGNATURE.HEADER_NAME] = sig.replace(/^Signature /, '') 67 const sig = req.headers[HTTP_SIGNATURE.HEADER_NAME] as string
67 68 if (sig && sig.startsWith('Signature ') === true) req.headers[HTTP_SIGNATURE.HEADER_NAME] = sig.replace(/^Signature /, '')
68 let parsed: any 69
69 70 let parsed: any
70 try { 71
71 parsed = parseHTTPSignature(req, HTTP_SIGNATURE.CLOCK_SKEW_SECONDS) 72 try {
72 } catch (err) { 73 parsed = parseHTTPSignature(req, HTTP_SIGNATURE.CLOCK_SKEW_SECONDS)
73 logger.warn('Invalid signature because of exception in signature parser', { reqBody: req.body, err }) 74 } catch (err) {
74 75 logger.warn('Invalid signature because of exception in signature parser', { reqBody: req.body, err })
75 res.fail({ 76
76 status: HttpStatusCode.FORBIDDEN_403, 77 res.fail({
77 message: err.message 78 status: HttpStatusCode.FORBIDDEN_403,
78 }) 79 message: err.message
79 return false 80 })
80 } 81 return false
82 }
81 83
82 const keyId = parsed.keyId 84 const keyId = parsed.keyId
83 if (!keyId) { 85 if (!keyId) {
84 res.fail({ 86 res.fail({
85 status: HttpStatusCode.FORBIDDEN_403, 87 status: HttpStatusCode.FORBIDDEN_403,
86 message: 'Invalid key ID', 88 message: 'Invalid key ID',
87 data: { 89 data: {
88 keyId 90 keyId
89 } 91 }
90 }) 92 })
91 return false 93 return false
92 } 94 }
93 95
94 logger.debug('Checking HTTP signature of actor %s...', keyId) 96 logger.debug('Checking HTTP signature of actor %s...', keyId)
95 97
96 let [ actorUrl ] = keyId.split('#') 98 let [ actorUrl ] = keyId.split('#')
97 if (actorUrl.startsWith('acct:')) { 99 if (actorUrl.startsWith('acct:')) {
98 actorUrl = await loadActorUrlOrGetFromWebfinger(actorUrl.replace(/^acct:/, '')) 100 actorUrl = await loadActorUrlOrGetFromWebfinger(actorUrl.replace(/^acct:/, ''))
99 } 101 }
100 102
101 const actor = await getOrCreateAPActor(actorUrl) 103 const actor = await getOrCreateAPActor(actorUrl)
102 104
103 const verified = isHTTPSignatureVerified(parsed, actor) 105 const verified = isHTTPSignatureVerified(parsed, actor)
104 if (verified !== true) { 106 if (verified !== true) {
105 logger.warn('Signature from %s is invalid', actorUrl, { parsed }) 107 logger.warn('Signature from %s is invalid', actorUrl, { parsed })
106 108
107 res.fail({ 109 res.fail({
108 status: HttpStatusCode.FORBIDDEN_403, 110 status: HttpStatusCode.FORBIDDEN_403,
109 message: 'Invalid signature', 111 message: 'Invalid signature',
110 data: { 112 data: {
111 actorUrl 113 actorUrl
112 } 114 }
113 }) 115 })
114 return false 116 return false
115 } 117 }
116 118
117 res.locals.signature = { actor } 119 res.locals.signature = { actor }
118 return true 120 return true
121 })
119} 122}
120 123
121async function checkJsonLDSignature (req: Request, res: Response) { 124async function checkJsonLDSignature (req: Request, res: Response) {
122 const signatureObject: ActivityPubSignature = req.body.signature 125 return wrapWithSpanAndContext('peertube.activitypub.JSONLDSignature', async () => {
123 126 const signatureObject: ActivityPubSignature = req.body.signature
124 if (!signatureObject || !signatureObject.creator) { 127
125 res.fail({ 128 if (!signatureObject || !signatureObject.creator) {
126 status: HttpStatusCode.FORBIDDEN_403, 129 res.fail({
127 message: 'Object and creator signature do not match' 130 status: HttpStatusCode.FORBIDDEN_403,
128 }) 131 message: 'Object and creator signature do not match'
129 return false 132 })
130 } 133 return false
134 }
131 135
132 const [ creator ] = signatureObject.creator.split('#') 136 const [ creator ] = signatureObject.creator.split('#')
133 137
134 logger.debug('Checking JsonLD signature of actor %s...', creator) 138 logger.debug('Checking JsonLD signature of actor %s...', creator)
135 139
136 const actor = await getOrCreateAPActor(creator) 140 const actor = await getOrCreateAPActor(creator)
137 const verified = await isJsonLDSignatureVerified(actor, req.body) 141 const verified = await isJsonLDSignatureVerified(actor, req.body)
138 142
139 if (verified !== true) { 143 if (verified !== true) {
140 logger.warn('Signature not verified.', req.body) 144 logger.warn('Signature not verified.', req.body)
141 145
142 res.fail({ 146 res.fail({
143 status: HttpStatusCode.FORBIDDEN_403, 147 status: HttpStatusCode.FORBIDDEN_403,
144 message: 'Signature could not be verified' 148 message: 'Signature could not be verified'
145 }) 149 })
146 return false 150 return false
147 } 151 }
148 152
149 res.locals.signature = { actor } 153 res.locals.signature = { actor }
150 return true 154 return true
155 })
151} 156}