File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -16,6 +16,26 @@ describe("base-64.utils", () => {
1616 expect ( fromBase64 ( "aGVsbG8=" ) ) . toBe ( "hello" ) ;
1717 } ) ;
1818
19+ test ( "should decode base64 with line breaks and surrounding whitespace" , ( ) => {
20+ expect ( fromBase64 ( "aGVs\nbG8=" ) ) . toBe ( "hello" ) ;
21+ expect ( fromBase64 ( "aGVs\r\nbG8=" ) ) . toBe ( "hello" ) ;
22+ expect ( fromBase64 ( " aGVsbG8= " ) ) . toBe ( "hello" ) ;
23+ } ) ;
24+
25+ test ( "should decode multiple base64 strings, one per line" , ( ) => {
26+ expect ( fromBase64 ( "aGVsbG8=\nd29ybGQ=" ) ) . toBe ( "hello\nworld" ) ;
27+ } ) ;
28+
29+ test ( "should decode PEM-style wrapped base64 as a single message" , ( ) => {
30+ const message =
31+ "hello world this is a longer message for testing pem wrap" ;
32+ const wrapped = Buffer . from ( message )
33+ . toString ( "base64" )
34+ . match ( / .{ 1 , 20 } / g) !
35+ . join ( "\n" ) ;
36+ expect ( fromBase64 ( wrapped ) ) . toBe ( message ) ;
37+ } ) ;
38+
1939 test ( "should throw an error for an invalid Base64 string" , ( ) => {
2040 expect ( ( ) => fromBase64 ( "invalid_base64" ) ) . toThrow (
2141 "Invalid Base64 input"
Original file line number Diff line number Diff line change @@ -6,13 +6,39 @@ export function toBase64(value: string) {
66 }
77}
88
9+ function decodeBase64Chunk ( value : string ) : string {
10+ const decoded = Buffer . from ( value , "base64" ) . toString ( "utf-8" ) ;
11+ if ( ! isPrintableASCII ( decoded ) ) {
12+ throw new Error ( "Decoded string contains non-printable characters" ) ;
13+ }
14+ return decoded ;
15+ }
16+
917export function fromBase64 ( value : string ) : string {
1018 try {
11- const decoded = Buffer . from ( value , "base64" ) . toString ( "utf-8" ) ;
12- if ( ! isPrintableASCII ( decoded ) ) {
13- throw new Error ( "Decoded string contains non-printable characters" ) ;
19+ const trimmed = value . trim ( ) ;
20+ if ( ! trimmed ) {
21+ return "" ;
22+ }
23+
24+ const lines = trimmed
25+ . split ( / \r ? \n / )
26+ . map ( ( line ) => line . trim ( ) )
27+ . filter ( Boolean ) ;
28+
29+ if ( lines . length > 1 ) {
30+ const stripped = trimmed . replace ( / \s / g, "" ) ;
31+ const singleDecoded = decodeBase64Chunk ( stripped ) ;
32+ const firstLineDecoded = decodeBase64Chunk ( lines [ 0 ] ) ;
33+
34+ // Multiple independent base64 strings (one per line) decode to the same
35+ // output as the first line when joined; PEM-style wrapped input does not.
36+ if ( singleDecoded === firstLineDecoded ) {
37+ return lines . map ( ( line ) => decodeBase64Chunk ( line ) ) . join ( "\n" ) ;
38+ }
1439 }
15- return decoded ;
40+
41+ return decodeBase64Chunk ( trimmed . replace ( / \s / g, "" ) ) ;
1642 } catch {
1743 throw new Error ( "Invalid Base64 input" ) ;
1844 }
You can’t perform that action at this time.
0 commit comments