mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
crypto.pem: add decode_only and general improvements to decoding (#18908)
This commit is contained in:
parent
511274a8d4
commit
d66b097ddc
@ -2,25 +2,50 @@ module pem
|
|||||||
|
|
||||||
import encoding.base64
|
import encoding.base64
|
||||||
|
|
||||||
|
// decode_only reads `data` and returns the first parsed PEM Block. `none` is returned
|
||||||
|
// when a header is expected, but not present or when a start of '-----BEGIN' or end of '-----END'
|
||||||
|
// can't be found.
|
||||||
|
//
|
||||||
|
// use decode if you still need the unparsed rest of the string.
|
||||||
|
[inline]
|
||||||
|
pub fn decode_only(data string) ?Block {
|
||||||
|
block, _ := decode_internal(data)?
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
// decode reads `data` and returns the first parsed PEM Block along with the rest of
|
// decode reads `data` and returns the first parsed PEM Block along with the rest of
|
||||||
// the string. `none` is returned when a header is expected, but not present
|
// the string. `none` is returned when a header is expected, but not present
|
||||||
// or when a start of '-----BEGIN' or end of '-----END' can't be found in `data`
|
// or when a start of '-----BEGIN' or end of '-----END' can't be found.
|
||||||
|
//
|
||||||
|
// use decode_only if you do not need the unparsed rest of the string.
|
||||||
|
[direct_array_access; inline]
|
||||||
pub fn decode(data string) ?(Block, string) {
|
pub fn decode(data string) ?(Block, string) {
|
||||||
|
block, rest := decode_internal(data)?
|
||||||
|
return block, rest[rest.index(pem_end)? + pem_end.len..].all_after_first(pem_eol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode_internal allows `decode` variations to deal with the rest of the data as
|
||||||
|
// they want to. for example Block.decode could have hindered performance with the final
|
||||||
|
// indexing into `rest` that `decode_partial` does.
|
||||||
|
[direct_array_access]
|
||||||
|
fn decode_internal(data string) ?(Block, string) {
|
||||||
|
// direct_array_access safety: since we use the string.index method here,
|
||||||
|
// we won't get an invalid index since it would otherwise return `none`
|
||||||
mut rest := data[data.index(pem_begin)?..]
|
mut rest := data[data.index(pem_begin)?..]
|
||||||
mut block := Block.new(rest[pem_begin.len..].all_before(pem_eol))
|
mut block := Block.new(rest[pem_begin.len..].all_before(pem_eol))
|
||||||
block.headers, rest = parse_headers(rest[pem_begin.len..].all_after(pem_eol).trim_left(' \n\t\v\f\r'))?
|
block.headers, rest = parse_headers(rest[pem_begin.len..].all_after(pem_eol).trim_left(' \n\t\v\f\r'))?
|
||||||
|
|
||||||
block_end_index := rest.index(pem_end)?
|
block_end_index := rest.index(pem_end)?
|
||||||
b64_data := rest[..block_end_index].replace_each(['\r', '', '\n', '', '\t', '', ' ', ''])
|
b64_data := rest[..block_end_index].replace_each(['\r', '', '\n', '', '\t', '', ' ', ''])
|
||||||
|
|
||||||
block_data_len := block_end_index / 4 * 3
|
block_data_len := block_end_index / 4 * 3
|
||||||
block.data = []u8{len: block_data_len, cap: block_data_len + 3, init: 0}
|
block.data = []u8{len: block_data_len, cap: block_data_len + 3, init: 0}
|
||||||
decoded_len := base64.decode_in_buffer(&b64_data, &block.data[0])
|
decoded_len := base64.decode_in_buffer(&b64_data, &block.data[0])
|
||||||
block.data = block.data[..decoded_len]
|
block.data = block.data[..decoded_len]
|
||||||
|
|
||||||
return block, rest[rest.index(pem_end)? + pem_end.len..].all_after_first(pem_eol)
|
return block, rest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[direct_array_access]
|
||||||
fn parse_headers(block string) ?(map[string][]string, string) {
|
fn parse_headers(block string) ?(map[string][]string, string) {
|
||||||
headers_str := block.all_before(pem_end).all_before('\n\n')
|
headers_str := block.all_before(pem_end).all_before('\n\n')
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ fn test_decode_rfc1421() {
|
|||||||
for i in 0 .. pem.test_data_rfc1421.len {
|
for i in 0 .. pem.test_data_rfc1421.len {
|
||||||
decoded, rest := decode(pem.test_data_rfc1421[i]) or { Block{}, '' }
|
decoded, rest := decode(pem.test_data_rfc1421[i]) or { Block{}, '' }
|
||||||
assert decoded == pem.expected_results_rfc1421[i]
|
assert decoded == pem.expected_results_rfc1421[i]
|
||||||
|
assert decoded == decode_only(pem.test_data_rfc1421[i]) or { Block{} }
|
||||||
assert rest == ''
|
assert rest == ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,6 +14,7 @@ fn test_decode() {
|
|||||||
for i in 0 .. pem.test_data.len {
|
for i in 0 .. pem.test_data.len {
|
||||||
decoded, rest := decode(pem.test_data[i]) or { Block{}, '' }
|
decoded, rest := decode(pem.test_data[i]) or { Block{}, '' }
|
||||||
assert decoded == pem.expected_results[i]
|
assert decoded == pem.expected_results[i]
|
||||||
|
assert decoded == decode_only(pem.test_data[i]) or { Block{} }
|
||||||
assert rest == pem.expected_rest[i]
|
assert rest == pem.expected_rest[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,6 +25,7 @@ fn test_encode_rfc1421() {
|
|||||||
decoded, rest := decode(encoded) or { Block{}, '' }
|
decoded, rest := decode(encoded) or { Block{}, '' }
|
||||||
assert rest == ''
|
assert rest == ''
|
||||||
assert decoded == pem.expected_results_rfc1421[i]
|
assert decoded == pem.expected_results_rfc1421[i]
|
||||||
|
assert decoded == decode_only(encoded) or { Block{} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ fn test_encode() {
|
|||||||
decoded, rest := decode(encoded) or { Block{}, '' }
|
decoded, rest := decode(encoded) or { Block{}, '' }
|
||||||
assert rest == ''
|
assert rest == ''
|
||||||
assert decoded == pem.expected_results[i]
|
assert decoded == pem.expected_results[i]
|
||||||
|
assert decoded == decode_only(encoded) or { Block{} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,15 +45,17 @@ fn test_encode_config() {
|
|||||||
decoded, rest := decode(encoded) or { Block{}, '' }
|
decoded, rest := decode(encoded) or { Block{}, '' }
|
||||||
assert rest == ''
|
assert rest == ''
|
||||||
assert decoded == pem.expected_results[i]
|
assert decoded == pem.expected_results[i]
|
||||||
|
assert decoded == decode_only(encoded) or { Block{} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_decode_no_pem() {
|
fn test_decode_no_pem() {
|
||||||
for test in pem.test_data_no_pem {
|
for test in pem.test_data_no_pem {
|
||||||
if _, _ := decode(test) {
|
if _, _ := decode(test) {
|
||||||
assert false, 'Block.decode_partial should return `none` on input without PEM data'
|
assert false, 'decode should return `none` on input without PEM data'
|
||||||
} else {
|
}
|
||||||
assert true
|
if _ := decode_only(test) {
|
||||||
|
assert false, 'decode_only should return `none` on input without PEM data'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user