Skip to content

Commit b765f3e

Browse files
iunanuatlhuntersimon-id
authored
Embed AppSec rules and templates files to be compatible with bundlers (#2913)
* gentle fallback if appsec template files are missing * Load appsec template files with require --------- Co-authored-by: Thomas Hunter II <tlhunter@datadog.com> Co-authored-by: simon-id <simon.id@datadoghq.com>
1 parent deda0c8 commit b765f3e

15 files changed

+170
-297
lines changed

packages/dd-trace/src/appsec/templates/blocked.html packages/dd-trace/src/appsec/blocked_templates.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
<!-- Sorry, you’ve been blocked -->
1+
/* eslint-disable max-len */
2+
'use strict'
3+
4+
const html = `<!-- Sorry, you've been blocked -->
25
<!DOCTYPE html>
36
<html lang="en">
47
@@ -97,3 +100,18 @@
97100
</body>
98101
99102
</html>
103+
`
104+
105+
const json = `{
106+
"errors": [
107+
{
108+
"title": "You've been blocked",
109+
"detail": "Sorry, you cannot access this page. Please contact the customer service team. Security provided by Datadog."
110+
}
111+
]
112+
}`
113+
114+
module.exports = {
115+
html,
116+
json
117+
}

packages/dd-trace/src/appsec/blocking.js

+9-24
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
'use strict'
22

33
const log = require('../log')
4-
const fs = require('fs')
4+
const blockedTemplates = require('./blocked_templates')
55

6-
// TODO: move template loading to a proper spot.
7-
let templateLoaded = false
8-
let templateHtml = ''
9-
let templateJson = ''
6+
let templateHtml = blockedTemplates.html
7+
let templateJson = blockedTemplates.json
108

119
function block (req, res, rootSpan, abortController) {
1210
if (res.headersSent) {
@@ -42,29 +40,16 @@ function block (req, res, rootSpan, abortController) {
4240
}
4341
}
4442

45-
function loadTemplates (config) {
46-
if (!templateLoaded) {
47-
templateHtml = fs.readFileSync(config.appsec.blockedTemplateHtml)
48-
templateJson = fs.readFileSync(config.appsec.blockedTemplateJson)
49-
templateLoaded = true
43+
function setTemplates (config) {
44+
if (config.appsec.blockedTemplateHtml) {
45+
templateHtml = config.appsec.blockedTemplateHtml
5046
}
51-
}
52-
53-
async function loadTemplatesAsync (config) {
54-
if (!templateLoaded) {
55-
templateHtml = await fs.promises.readFile(config.appsec.blockedTemplateHtml)
56-
templateJson = await fs.promises.readFile(config.appsec.blockedTemplateJson)
57-
templateLoaded = true
47+
if (config.appsec.blockedTemplateJson) {
48+
templateJson = config.appsec.blockedTemplateJson
5849
}
5950
}
6051

61-
function resetTemplates () {
62-
templateLoaded = false
63-
}
64-
6552
module.exports = {
6653
block,
67-
loadTemplates,
68-
loadTemplatesAsync,
69-
resetTemplates
54+
setTemplates
7055
}

packages/dd-trace/src/appsec/index.js

+4-18
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
'use strict'
22

3-
const fs = require('fs')
4-
const path = require('path')
53
const log = require('../log')
64
const RuleManager = require('./rule_manager')
75
const remoteConfig = require('./remote_config')
@@ -12,7 +10,7 @@ const Reporter = require('./reporter')
1210
const web = require('../plugins/util/web')
1311
const { extractIp } = require('../plugins/util/ip_extractor')
1412
const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
15-
const { block, loadTemplates, loadTemplatesAsync } = require('./blocking')
13+
const { block, setTemplates } = require('./blocking')
1614

1715
let isEnabled = false
1816
let config
@@ -21,21 +19,10 @@ function enable (_config) {
2119
if (isEnabled) return
2220

2321
try {
24-
loadTemplates(_config)
25-
const rules = fs.readFileSync(_config.appsec.rules || path.join(__dirname, 'recommended.json'))
26-
enableFromRules(_config, JSON.parse(rules))
27-
} catch (err) {
28-
abortEnable(err)
29-
}
30-
}
22+
setTemplates(_config)
3123

32-
async function enableAsync (_config) {
33-
if (isEnabled) return
34-
35-
try {
36-
await loadTemplatesAsync(_config)
37-
const rules = await fs.promises.readFile(_config.appsec.rules || path.join(__dirname, 'recommended.json'))
38-
enableFromRules(_config, JSON.parse(rules))
24+
const rules = _config.appsec.rules || require('./recommended.json')
25+
enableFromRules(_config, rules)
3926
} catch (err) {
4027
abortEnable(err)
4128
}
@@ -169,7 +156,6 @@ function disable () {
169156

170157
module.exports = {
171158
enable,
172-
enableAsync,
173159
disable,
174160
incomingHttpStartTranslator,
175161
incomingHttpEndTranslator

packages/dd-trace/src/appsec/remote_config/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function enable (config) {
2323
}
2424

2525
if (shouldEnable) {
26-
require('..').enableAsync(config).catch(() => {})
26+
require('..').enable(config)
2727
} else {
2828
require('..').disable()
2929
}

packages/dd-trace/src/appsec/sdk/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
const { trackUserLoginSuccessEvent, trackUserLoginFailureEvent, trackCustomEvent } = require('./track_event')
44
const { checkUserAndSetUser, blockRequest } = require('./user_blocking')
5-
const { loadTemplates } = require('../blocking')
5+
const { setTemplates } = require('../blocking')
66
const { setUser } = require('./set_user')
77

88
class AppsecSdk {
99
constructor (tracer, config) {
1010
this._tracer = tracer
1111
if (config) {
12-
loadTemplates(config)
12+
setTemplates(config)
1313
}
1414
}
1515

packages/dd-trace/src/appsec/templates/blocked.json

-8
This file was deleted.

packages/dd-trace/src/config.js

+7-19
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const coalesce = require('koalas')
99
const tagger = require('./tagger')
1010
const { isTrue, isFalse } = require('./util')
1111
const uuid = require('crypto-randomuuid')
12-
const path = require('path')
1312

1413
const fromEntries = Object.fromEntries || (entries =>
1514
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
@@ -22,16 +21,7 @@ function maybeFile (filepath) {
2221
try {
2322
return fs.readFileSync(filepath, 'utf8')
2423
} catch (e) {
25-
return undefined
26-
}
27-
}
28-
29-
function maybePath (filepath) {
30-
if (!filepath) return
31-
try {
32-
fs.openSync(filepath, 'r')
33-
return filepath
34-
} catch (e) {
24+
log.error(e)
3525
return undefined
3626
}
3727
}
@@ -310,8 +300,8 @@ class Config {
310300
)
311301

312302
const DD_APPSEC_RULES = coalesce(
313-
appsec.rules,
314-
process.env.DD_APPSEC_RULES
303+
safeJsonParse(maybeFile(appsec.rules)),
304+
safeJsonParse(maybeFile(process.env.DD_APPSEC_RULES))
315305
)
316306
const DD_APPSEC_TRACE_RATE_LIMIT = coalesce(
317307
parseInt(appsec.rateLimit),
@@ -338,14 +328,12 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
338328
|[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}`
339329
)
340330
const DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML = coalesce(
341-
maybePath(appsec.blockedTemplateHtml),
342-
maybePath(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML),
343-
path.join(__dirname, 'appsec', 'templates', 'blocked.html')
331+
maybeFile(appsec.blockedTemplateHtml),
332+
maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML)
344333
)
345334
const DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON = coalesce(
346-
maybePath(appsec.blockedTemplateJson),
347-
maybePath(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON),
348-
path.join(__dirname, 'appsec', 'templates', 'blocked.json')
335+
maybeFile(appsec.blockedTemplateJson),
336+
maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
349337
)
350338

351339
const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined

0 commit comments

Comments
 (0)