UNPKG

4.12 kBJavaScriptView Raw
1const isObject = require('../help/is_object')
2let validateCrit = require('../help/validate_crit')
3
4const { JWEInvalid } = require('../errors')
5
6validateCrit = validateCrit.bind(undefined, JWEInvalid)
7
8const compactSerializer = (final, [recipient]) => {
9 return `${final.protected}.${recipient.encrypted_key}.${final.iv}.${final.ciphertext}.${final.tag}`
10}
11compactSerializer.validate = (protectedHeader, unprotectedHeader, aad, { 0: { header }, length }) => {
12 if (length !== 1 || aad || unprotectedHeader || header) {
13 throw new JWEInvalid('JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD')
14 }
15 validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined)
16}
17
18const flattenedSerializer = (final, [recipient]) => {
19 const { header, encrypted_key: encryptedKey } = recipient
20
21 return {
22 ...(final.protected ? { protected: final.protected } : undefined),
23 ...(final.unprotected ? { unprotected: final.unprotected } : undefined),
24 ...(header ? { header } : undefined),
25 ...(encryptedKey ? { encrypted_key: encryptedKey } : undefined),
26 ...(final.aad ? { aad: final.aad } : undefined),
27 iv: final.iv,
28 ciphertext: final.ciphertext,
29 tag: final.tag
30 }
31}
32flattenedSerializer.validate = (protectedHeader, unprotectedHeader, aad, { 0: { header }, length }) => {
33 if (length !== 1) {
34 throw new JWEInvalid('Flattened JWE JSON Serialization doesn\'t support multiple recipients')
35 }
36 validateCrit(protectedHeader, { ...unprotectedHeader, ...header }, protectedHeader ? protectedHeader.crit : undefined)
37}
38
39const generalSerializer = (final, recipients) => {
40 const result = {
41 ...(final.protected ? { protected: final.protected } : undefined),
42 ...(final.unprotected ? { unprotected: final.unprotected } : undefined),
43 recipients: recipients.map(({ header, encrypted_key: encryptedKey, generatedHeader }) => {
44 if (!header && !encryptedKey && !generatedHeader) {
45 return false
46 }
47
48 return {
49 ...(header || generatedHeader ? { header: { ...header, ...generatedHeader } } : undefined),
50 ...(encryptedKey ? { encrypted_key: encryptedKey } : undefined)
51 }
52 }).filter(Boolean),
53 ...(final.aad ? { aad: final.aad } : undefined),
54 iv: final.iv,
55 ciphertext: final.ciphertext,
56 tag: final.tag
57 }
58
59 if (!result.recipients.length) {
60 delete result.recipients
61 }
62
63 return result
64}
65generalSerializer.validate = (protectedHeader, unprotectedHeader, aad, recipients) => {
66 recipients.forEach(({ header }) => {
67 validateCrit(protectedHeader, { ...header, ...unprotectedHeader }, protectedHeader ? protectedHeader.crit : undefined)
68 })
69}
70
71const isJSON = (input) => {
72 return isObject(input) &&
73 typeof input.ciphertext === 'string' &&
74 typeof input.iv === 'string' &&
75 typeof input.tag === 'string' &&
76 (input.unprotected === undefined || isObject(input.unprotected)) &&
77 (input.protected === undefined || typeof input.protected === 'string') &&
78 (input.aad === undefined || typeof input.aad === 'string')
79}
80
81const isSingleRecipient = (input) => {
82 return (input.encrypted_key === undefined || typeof input.encrypted_key === 'string') &&
83 (input.header === undefined || isObject(input.header))
84}
85
86const isValidRecipient = (recipient) => {
87 return isObject(recipient) && typeof recipient.encrypted_key === 'string' && (recipient.header === undefined || isObject(recipient.header))
88}
89
90const isMultiRecipient = (input) => {
91 if (Array.isArray(input.recipients) && input.recipients.every(isValidRecipient)) {
92 return true
93 }
94
95 return false
96}
97
98const detect = (input) => {
99 if (typeof input === 'string' && input.split('.').length === 5) {
100 return 'compact'
101 }
102
103 if (isJSON(input)) {
104 if (isMultiRecipient(input)) {
105 return 'general'
106 }
107
108 if (isSingleRecipient(input)) {
109 return 'flattened'
110 }
111 }
112
113 throw new JWEInvalid('JWE malformed or invalid serialization')
114}
115
116module.exports = {
117 compact: compactSerializer,
118 flattened: flattenedSerializer,
119 general: generalSerializer,
120 detect
121}