1 | const isObject = require('../help/is_object')
|
2 | let validateCrit = require('../help/validate_crit')
|
3 | const { JWSInvalid } = require('../errors')
|
4 |
|
5 | validateCrit = validateCrit.bind(undefined, JWSInvalid)
|
6 |
|
7 | const compactSerializer = (payload, [recipient]) => {
|
8 | return `${recipient.protected}.${payload}.${recipient.signature}`
|
9 | }
|
10 | compactSerializer.validate = (jws, { 0: { unprotectedHeader, protectedHeader }, length }) => {
|
11 | if (length !== 1 || unprotectedHeader) {
|
12 | throw new JWSInvalid('JWS Compact Serialization doesn\'t support multiple recipients or JWS unprotected headers')
|
13 | }
|
14 | validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined)
|
15 | }
|
16 |
|
17 | const flattenedSerializer = (payload, [recipient]) => {
|
18 | const { header, signature, protected: prot } = recipient
|
19 |
|
20 | return {
|
21 | payload,
|
22 | ...prot ? { protected: prot } : undefined,
|
23 | ...header ? { header } : undefined,
|
24 | signature
|
25 | }
|
26 | }
|
27 | flattenedSerializer.validate = (jws, { 0: { unprotectedHeader, protectedHeader }, length }) => {
|
28 | if (length !== 1) {
|
29 | throw new JWSInvalid('Flattened JWS JSON Serialization doesn\'t support multiple recipients')
|
30 | }
|
31 | validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined)
|
32 | }
|
33 |
|
34 | const generalSerializer = (payload, recipients) => {
|
35 | return {
|
36 | payload,
|
37 | signatures: recipients.map(({ header, signature, protected: prot }) => {
|
38 | return {
|
39 | ...prot ? { protected: prot } : undefined,
|
40 | ...header ? { header } : undefined,
|
41 | signature
|
42 | }
|
43 | })
|
44 | }
|
45 | }
|
46 | generalSerializer.validate = (jws, recipients) => {
|
47 | recipients.forEach(({ protectedHeader, unprotectedHeader }) => {
|
48 | validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined)
|
49 | })
|
50 | }
|
51 |
|
52 | const isJSON = (input) => {
|
53 | return isObject(input) && (typeof input.payload === 'string' || Buffer.isBuffer(input.payload))
|
54 | }
|
55 |
|
56 | const isValidRecipient = (recipient) => {
|
57 | return isObject(recipient) && typeof recipient.signature === 'string' &&
|
58 | (recipient.header === undefined || isObject(recipient.header)) &&
|
59 | (recipient.protected === undefined || typeof recipient.protected === 'string')
|
60 | }
|
61 |
|
62 | const isMultiRecipient = (input) => {
|
63 | if (Array.isArray(input.signatures) && input.signatures.every(isValidRecipient)) {
|
64 | return true
|
65 | }
|
66 |
|
67 | return false
|
68 | }
|
69 |
|
70 | const detect = (input) => {
|
71 | if (typeof input === 'string' && input.split('.').length === 3) {
|
72 | return 'compact'
|
73 | }
|
74 |
|
75 | if (isJSON(input)) {
|
76 | if (isMultiRecipient(input)) {
|
77 | return 'general'
|
78 | }
|
79 |
|
80 | if (isValidRecipient(input)) {
|
81 | return 'flattened'
|
82 | }
|
83 | }
|
84 |
|
85 | throw new JWSInvalid('JWS malformed or invalid serialization')
|
86 | }
|
87 |
|
88 | module.exports = {
|
89 | compact: compactSerializer,
|
90 | flattened: flattenedSerializer,
|
91 | general: generalSerializer,
|
92 | detect
|
93 | }
|