npq 3.21.0 → 3.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const BaseMarshall = require('./baseMarshall')
|
|
4
4
|
const { marshallCategories } = require('./constants')
|
|
5
|
+
const NotEvaluated = require('../helpers/notEvaluated')
|
|
5
6
|
const { Resolver } = require('dns/promises')
|
|
6
7
|
|
|
7
8
|
const dns = new Resolver()
|
|
@@ -13,37 +14,62 @@ class Marshall extends BaseMarshall {
|
|
|
13
14
|
super(options)
|
|
14
15
|
this.name = MARSHALL_NAME
|
|
15
16
|
this.categoryId = marshallCategories.PackageHealth.id
|
|
17
|
+
this.dnsResolver = options.dnsResolver || dns
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
title() {
|
|
19
21
|
return 'Detecting expired domains for authors account...'
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
validate(pkg) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
async validate(pkg) {
|
|
25
|
+
const data = await this.packageRepoUtils.getPackageInfo(pkg.packageName)
|
|
26
|
+
const lastVersionData =
|
|
27
|
+
data.versions && data['dist-tags'] && data.versions[data['dist-tags'].latest]
|
|
28
|
+
|
|
29
|
+
const maintainersAccounts = lastVersionData && lastVersionData.maintainers
|
|
30
|
+
|
|
31
|
+
if (!Array.isArray(maintainersAccounts) || maintainersAccounts.length === 0) {
|
|
32
|
+
throw new NotEvaluated('no maintainers information available for the package')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const emailDomains = []
|
|
36
|
+
let invalidMaintainers = 0
|
|
37
|
+
for (const maintainerInfo of maintainersAccounts) {
|
|
38
|
+
const maintainerEmail = maintainerInfo && maintainerInfo.email
|
|
39
|
+
const atIndex = typeof maintainerEmail === 'string' ? maintainerEmail.lastIndexOf('@') : -1
|
|
40
|
+
const emailDomain = atIndex > 0 ? maintainerEmail.slice(atIndex + 1).trim() : ''
|
|
41
|
+
|
|
42
|
+
if (!emailDomain || emailDomain.includes('@') || /\s/.test(emailDomain)) {
|
|
43
|
+
invalidMaintainers += 1
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
emailDomains.push(emailDomain)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (emailDomains.length === 0) {
|
|
51
|
+
throw new NotEvaluated('no valid maintainer email domains are available for the package')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let resolutionResults
|
|
55
|
+
try {
|
|
56
|
+
resolutionResults = await Promise.all(
|
|
57
|
+
emailDomains.map((emailDomain) => this.dnsResolver.resolve(emailDomain, 'NS'))
|
|
58
|
+
)
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const emailHostname = error.hostname ? error.hostname : '<unknown>'
|
|
61
|
+
this.debug('\nDetected error resolving domain for maintainer e-mail: %s', emailHostname)
|
|
62
|
+
throw new Error(
|
|
63
|
+
'Detected expired domain can be abused for account takeover: ' + emailHostname
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (invalidMaintainers > 0) {
|
|
68
|
+
const noun = invalidMaintainers === 1 ? 'address is' : 'addresses are'
|
|
69
|
+
throw new NotEvaluated(`${invalidMaintainers} maintainer email ${noun} missing or malformed`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return resolutionResults
|
|
47
73
|
}
|
|
48
74
|
}
|
|
49
75
|
|