1
1
import { ChecksumConstructor } from "@smithy/types" ;
2
2
import * as crypto from "crypto" ;
3
3
4
- import { ssecMiddleware } from "./" ;
4
+ import { isValidBase64EncodedSSECustomerKey , ssecMiddleware } from "./" ;
5
5
6
6
describe ( "ssecMiddleware" , ( ) => {
7
7
const next = jest . fn ( ) ;
@@ -28,22 +28,16 @@ describe("ssecMiddleware", () => {
28
28
} ) ;
29
29
30
30
it ( "should base64 encode input keys and set respective MD5 inputs" , async ( ) => {
31
- encoder1 . mockReturnValue ( "/+JF8FMG8UVMWSaNz0s6Wg==" ) ;
32
- const key = "TestKey123" ;
33
- const binaryRepresentationOfKey = Buffer . from ( key ) ;
34
- const base64Key = binaryRepresentationOfKey . toString ( "base64" ) ;
35
- const md5Hash = crypto . createHash ( "md5" ) . update ( binaryRepresentationOfKey ) . digest ( ) ;
36
- const base64Md5Hash = Buffer . from ( md5Hash ) . toString ( "base64" ) ;
37
-
31
+ encoder2 . mockReturnValue ( "base64" ) ;
38
32
const args = {
39
33
input : {
40
- SSECustomerKey : base64Key ,
41
- CopySourceSSECustomerKey : base64Key ,
34
+ SSECustomerKey : "foo" ,
35
+ CopySourceSSECustomerKey : "bar" ,
42
36
} ,
43
37
} ;
44
38
45
39
const handler = ssecMiddleware ( {
46
- base64Encoder : encoder1 ,
40
+ base64Encoder : encoder2 ,
47
41
utf8Decoder : decoder ,
48
42
md5 : MockHash ,
49
43
base64Decoder : base64Decoder ,
@@ -54,49 +48,147 @@ describe("ssecMiddleware", () => {
54
48
expect ( next . mock . calls . length ) . toBe ( 1 ) ;
55
49
expect ( next ) . toHaveBeenCalledWith ( {
56
50
input : {
57
- SSECustomerKey : base64Key ,
58
- SSECustomerKeyMD5 : base64Md5Hash ,
59
- CopySourceSSECustomerKey : base64Key ,
60
- CopySourceSSECustomerKeyMD5 : base64Md5Hash ,
51
+ SSECustomerKey : "base64" ,
52
+ SSECustomerKeyMD5 : "base64" ,
53
+ CopySourceSSECustomerKey : "base64" ,
54
+ CopySourceSSECustomerKeyMD5 : "base64" ,
61
55
} ,
62
56
} ) ;
63
- expect ( decoder . mock . calls . length ) . toBe ( 0 ) ;
64
- expect ( encoder1 . mock . calls . length ) . toBe ( 2 ) ;
57
+ expect ( decoder . mock . calls . length ) . toBe ( 2 ) ;
58
+ expect ( encoder2 . mock . calls . length ) . toBe ( 4 ) ;
65
59
expect ( mockHashUpdate . mock . calls . length ) . toBe ( 2 ) ;
66
60
expect ( mockHashDigest . mock . calls . length ) . toBe ( 2 ) ;
67
- encoder1 . mockClear ( ) ;
61
+ encoder2 . mockClear ( ) ;
68
62
} ) ;
69
- it ( "should base64 encode input keys and set respective MD5 inputs" , async ( ) => {
70
- encoder2 . mockReturnValue ( "base64" ) ;
63
+
64
+ it ( "should handle valid base64 encoded 32byte key input for SSECustomerKey and CopySourceSSECustomerKey" , async ( ) => {
65
+ const validBase64EncodedKey = "QUIwMTIzNDU2Nzg5QUJDREVGQUJDREVGQUJDREVGQUI=" ;
66
+ const decodedBytes = Buffer . from ( validBase64EncodedKey , "base64" ) ;
67
+ const md5Hash = crypto . createHash ( "md5" ) . update ( decodedBytes ) . digest ( ) ;
68
+ const base64EncodedMD5Hash = Buffer . from ( md5Hash ) . toString ( "base64" ) ;
69
+
70
+ base64Decoder . mockReturnValue ( decodedBytes ) ;
71
+ const mockMD5Instance = {
72
+ update : jest . fn ( ) . mockReturnThis ( ) ,
73
+ digest : jest . fn ( ) . mockReturnValue ( md5Hash ) ,
74
+ } ;
75
+ const mockMD5Constructor = jest . fn ( ) . mockReturnValue ( mockMD5Instance ) ;
76
+ const base64Encoder = jest . fn ( ) . mockReturnValue ( base64EncodedMD5Hash ) ;
77
+
78
+ const handler = ssecMiddleware ( {
79
+ base64Encoder,
80
+ utf8Decoder : decoder ,
81
+ md5 : mockMD5Constructor ,
82
+ base64Decoder,
83
+ } ) ( next , { } as any ) ;
84
+
71
85
const args = {
72
86
input : {
73
- SSECustomerKey : "foo" ,
74
- CopySourceSSECustomerKey : "bar" ,
87
+ SSECustomerKey : validBase64EncodedKey ,
88
+ CopySourceSSECustomerKey : validBase64EncodedKey ,
75
89
} ,
76
90
} ;
77
91
92
+ await handler ( args ) ;
93
+
94
+ expect ( next ) . toHaveBeenCalledTimes ( 1 ) ;
95
+ expect ( next ) . toHaveBeenCalledWith ( {
96
+ input : {
97
+ SSECustomerKey : validBase64EncodedKey ,
98
+ SSECustomerKeyMD5 : base64EncodedMD5Hash ,
99
+ CopySourceSSECustomerKey : validBase64EncodedKey ,
100
+ CopySourceSSECustomerKeyMD5 : base64EncodedMD5Hash ,
101
+ } ,
102
+ } ) ;
103
+
104
+ expect ( base64Decoder ) . toHaveBeenCalledTimes ( 4 ) ;
105
+ expect ( base64Decoder ) . toHaveBeenCalledWith ( validBase64EncodedKey ) ;
106
+ expect ( mockMD5Constructor ) . toHaveBeenCalledTimes ( 2 ) ;
107
+ expect ( mockMD5Instance . update ) . toHaveBeenCalledTimes ( 2 ) ;
108
+ expect ( mockMD5Instance . update ) . toHaveBeenCalledWith ( decodedBytes ) ;
109
+ expect ( mockMD5Instance . digest ) . toHaveBeenCalledTimes ( 2 ) ;
110
+ expect ( base64Encoder ) . toHaveBeenCalledTimes ( 2 ) ;
111
+ expect ( base64Encoder ) . toHaveBeenCalledWith ( md5Hash ) ;
112
+ } ) ;
113
+
114
+ it ( "should handle 32-byte binary key input for SSECustomerKey and CopySourceSSECustomerKey" , async ( ) => {
115
+ const binaryKey = crypto . randomBytes ( 32 ) ;
116
+ const md5Hash = crypto . createHash ( "md5" ) . update ( binaryKey ) . digest ( ) ;
117
+ const base64EncodedKey = binaryKey . toString ( "base64" ) ;
118
+ const base64EncodedMD5Hash = md5Hash . toString ( "base64" ) ;
119
+
120
+ const mockMD5Constructor = jest . fn ( ) . mockReturnValue ( {
121
+ update : jest . fn ( ) . mockReturnThis ( ) ,
122
+ digest : jest . fn ( ) . mockReturnValueOnce ( md5Hash ) . mockReturnValueOnce ( md5Hash ) ,
123
+ } ) ;
124
+
125
+ const base64Encoder = jest
126
+ . fn ( )
127
+ . mockReturnValueOnce ( base64EncodedKey )
128
+ . mockReturnValueOnce ( base64EncodedMD5Hash )
129
+ . mockReturnValueOnce ( base64EncodedKey )
130
+ . mockReturnValueOnce ( base64EncodedMD5Hash ) ;
131
+
78
132
const handler = ssecMiddleware ( {
79
- base64Encoder : encoder2 ,
133
+ base64Encoder,
80
134
utf8Decoder : decoder ,
81
- md5 : MockHash ,
82
- base64Decoder : base64Decoder ,
135
+ md5 : mockMD5Constructor ,
136
+ base64Decoder,
83
137
} ) ( next , { } as any ) ;
84
138
139
+ const args = {
140
+ input : {
141
+ SSECustomerKey : binaryKey ,
142
+ CopySourceSSECustomerKey : binaryKey ,
143
+ } ,
144
+ } ;
145
+
85
146
await handler ( args ) ;
86
147
87
- expect ( next . mock . calls . length ) . toBe ( 1 ) ;
148
+ expect ( next ) . toHaveBeenCalledTimes ( 1 ) ;
88
149
expect ( next ) . toHaveBeenCalledWith ( {
89
150
input : {
90
- SSECustomerKey : "base64" ,
91
- SSECustomerKeyMD5 : "base64" ,
92
- CopySourceSSECustomerKey : "base64" ,
93
- CopySourceSSECustomerKeyMD5 : "base64" ,
151
+ SSECustomerKey : base64EncodedKey ,
152
+ SSECustomerKeyMD5 : base64EncodedMD5Hash ,
153
+ CopySourceSSECustomerKey : base64EncodedKey ,
154
+ CopySourceSSECustomerKeyMD5 : base64EncodedMD5Hash ,
94
155
} ,
95
156
} ) ;
96
- expect ( decoder . mock . calls . length ) . toBe ( 2 ) ;
97
- expect ( encoder2 . mock . calls . length ) . toBe ( 4 ) ;
98
- expect ( mockHashUpdate . mock . calls . length ) . toBe ( 2 ) ;
99
- expect ( mockHashDigest . mock . calls . length ) . toBe ( 2 ) ;
100
- encoder2 . mockClear ( ) ;
157
+
158
+ expect ( mockMD5Constructor ) . toHaveBeenCalledTimes ( 2 ) ;
159
+ expect ( base64Encoder ) . toHaveBeenCalledTimes ( 4 ) ;
160
+ } ) ;
161
+
162
+ it ( "should return false for an invalid base64 string" , ( ) => {
163
+ const invalidBase64 = "invalid!@#$%" ;
164
+ const base64Decoder = jest . fn ( ) ;
165
+ const options = { base64Decoder } ;
166
+
167
+ const result = isValidBase64EncodedSSECustomerKey ( invalidBase64 , options as any ) ;
168
+ expect ( result ) . toBe ( false ) ;
169
+ expect ( base64Decoder ) . not . toHaveBeenCalled ( ) ;
170
+ } ) ;
171
+
172
+ it ( "should return true for a valid base64 string and 32 bytes" , ( ) => {
173
+ const validBase64EncodedSSECustomerKey = "QUIwMTIzNDU2Nzg5QUJDREVGQUJDREVGQUJDREVGQUI=" ;
174
+ const decodedBytes = new Uint8Array ( 32 ) ;
175
+ const base64Decoder = jest . fn ( ) . mockReturnValue ( decodedBytes ) ;
176
+ const options = { base64Decoder } ;
177
+
178
+ const result = isValidBase64EncodedSSECustomerKey ( validBase64EncodedSSECustomerKey , options as any ) ;
179
+ expect ( result ) . toBe ( true ) ;
180
+ expect ( base64Decoder ) . toHaveBeenCalledTimes ( 1 ) ;
181
+ expect ( base64Decoder ) . toHaveBeenCalledWith ( validBase64EncodedSSECustomerKey ) ;
182
+ } ) ;
183
+
184
+ it ( "should return false for a valid base64 string but not 32 bytes" , ( ) => {
185
+ const validBase64NonThirtyTwoBytes = "SGVsbG8=" ;
186
+ const base64Decoder = jest . fn ( ) . mockReturnValue ( new Uint8Array ( [ 72 , 101 , 108 , 108 , 111 ] ) ) ;
187
+ const options = { base64Decoder } ;
188
+
189
+ const result = isValidBase64EncodedSSECustomerKey ( validBase64NonThirtyTwoBytes , options as any ) ;
190
+ expect ( result ) . toBe ( false ) ;
191
+ expect ( base64Decoder ) . toHaveBeenCalledTimes ( 1 ) ;
192
+ expect ( base64Decoder ) . toHaveBeenCalledWith ( validBase64NonThirtyTwoBytes ) ;
101
193
} ) ;
102
194
} ) ;
0 commit comments