mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-01 13:49:16 +00:00
Everywhere: Hoist the Libraries folder to the top-level
This commit is contained in:
parent
950e819ee7
commit
93712b24bf
Notes:
github-actions[bot]
2024-11-10 11:51:52 +00:00
Author: https://github.com/trflynn89
Commit: 93712b24bf
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2256
Reviewed-by: https://github.com/sideshowbarker
4547 changed files with 104 additions and 113 deletions
191
Libraries/LibWeb/SRI/SRI.cpp
Normal file
191
Libraries/LibWeb/SRI/SRI.cpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/Base64.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCrypto/Hash/SHA2.h>
|
||||
#include <LibWeb/SRI/SRI.h>
|
||||
|
||||
namespace Web::SRI {
|
||||
|
||||
constexpr Array supported_hash_functions {
|
||||
// These are sorted by strength, low to high.
|
||||
// NOTE: We are specifically told to refuse MD5 and SHA1.
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#hash-functions
|
||||
"sha256"sv,
|
||||
"sha384"sv,
|
||||
"sha512"sv,
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#getprioritizedhashfunction
|
||||
static StringView get_prioritized_hash_function(StringView a, StringView b)
|
||||
{
|
||||
if (a == b)
|
||||
return ""sv;
|
||||
|
||||
auto a_priority = supported_hash_functions.first_index_of(a).value();
|
||||
auto b_priority = supported_hash_functions.first_index_of(b).value();
|
||||
if (a_priority > b_priority)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#apply-algorithm-to-response
|
||||
ErrorOr<String> apply_algorithm_to_bytes(StringView algorithm, ByteBuffer const& bytes)
|
||||
{
|
||||
// NOTE: The steps are duplicated here because each hash algorithm returns a different result type.
|
||||
|
||||
if (algorithm == "sha256"sv) {
|
||||
// 1. Let result be the result of applying algorithm to bytes.
|
||||
auto result = Crypto::Hash::SHA256::hash(bytes);
|
||||
|
||||
// 2. Return the result of base64 encoding result.
|
||||
return encode_base64(result.bytes());
|
||||
}
|
||||
|
||||
if (algorithm == "sha384"sv) {
|
||||
// 1. Let result be the result of applying algorithm to bytes.
|
||||
auto result = Crypto::Hash::SHA384::hash(bytes);
|
||||
|
||||
// 2. Return the result of base64 encoding result.
|
||||
return encode_base64(result.bytes());
|
||||
}
|
||||
|
||||
if (algorithm == "sha512"sv) {
|
||||
// 1. Let result be the result of applying algorithm to bytes.
|
||||
auto result = Crypto::Hash::SHA512::hash(bytes);
|
||||
|
||||
// 2. Return the result of base64 encoding result.
|
||||
return encode_base64(result.bytes());
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
|
||||
ErrorOr<Vector<Metadata>> parse_metadata(StringView metadata)
|
||||
{
|
||||
// 1. Let result be the empty set.
|
||||
Vector<Metadata> result;
|
||||
|
||||
// 2. For each item returned by splitting metadata on spaces:
|
||||
TRY(metadata.for_each_split_view(' ', SplitBehavior::Nothing, [&](StringView item) -> ErrorOr<void> {
|
||||
// 1. Let hash-with-opt-token-list be the result of splitting item on U+003F (?).
|
||||
auto hash_with_opt_token_list = item.split_view('?');
|
||||
|
||||
// 2. Let hash-expression be hash-with-opt-token-list[0].
|
||||
auto hash_expression = hash_with_opt_token_list[0];
|
||||
|
||||
// 3. Let base64-value be the empty string.
|
||||
StringView base64_value;
|
||||
|
||||
// 4. Let hash-expr-token-list be the result of splitting hash-expression on U+002D (-).
|
||||
auto hash_expr_token_list = hash_expression.split_view('-');
|
||||
|
||||
// 5. Let algorithm be hash-expr-token-list[0].
|
||||
auto algorithm = hash_expr_token_list[0];
|
||||
|
||||
// 6. If hash-expr-token-list[1] exists, set base64-value to hash-expr-token-list[1].
|
||||
if (hash_expr_token_list.size() >= 1)
|
||||
base64_value = hash_expr_token_list[1];
|
||||
|
||||
// 7. If algorithm is not a hash function recognized by the user agent, continue.
|
||||
if (!supported_hash_functions.contains_slow(algorithm))
|
||||
return {};
|
||||
|
||||
// 8. Let metadata be the ordered map «["alg" → algorithm, "val" → base64-value]».
|
||||
// Note: Since no options are defined (see the §3.1 Integrity metadata), a corresponding entry is not set in metadata.
|
||||
// If options are defined in a future version, hash-with-opt-token-list[1] can be utilized as options.
|
||||
auto metadata = Metadata {
|
||||
.algorithm = TRY(String::from_utf8(algorithm)),
|
||||
.base64_value = TRY(String::from_utf8(base64_value)),
|
||||
.options = {},
|
||||
};
|
||||
|
||||
// 9. Append metadata to result.
|
||||
TRY(result.try_append(move(metadata)));
|
||||
|
||||
return {};
|
||||
}));
|
||||
|
||||
// 3. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#get-the-strongest-metadata
|
||||
ErrorOr<Vector<Metadata>> get_strongest_metadata_from_set(Vector<Metadata> const& set)
|
||||
{
|
||||
// 1. Let result be the empty set and strongest be the empty string.
|
||||
Vector<Metadata> result;
|
||||
Optional<Metadata> strongest;
|
||||
|
||||
// 2. For each item in set:
|
||||
for (auto const& item : set) {
|
||||
// 1. If result is the empty set, add item to result and set strongest to item, skip to the next item.
|
||||
if (result.is_empty()) {
|
||||
TRY(result.try_append(item));
|
||||
strongest = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. Let currentAlgorithm be the alg component of strongest.
|
||||
auto& current_algorithm = strongest->algorithm;
|
||||
|
||||
// 3. Let newAlgorithm be the alg component of item.
|
||||
auto& new_algorithm = item.algorithm;
|
||||
|
||||
// 4. If the result of getPrioritizedHashFunction(currentAlgorithm, newAlgorithm) is the empty string, add item to result.
|
||||
auto prioritized_hash_function = get_prioritized_hash_function(current_algorithm, new_algorithm);
|
||||
if (prioritized_hash_function.is_empty()) {
|
||||
TRY(result.try_append(item));
|
||||
}
|
||||
// If the result is newAlgorithm, set strongest to item, set result to the empty set, and add item to result.
|
||||
else if (prioritized_hash_function == new_algorithm) {
|
||||
strongest = item;
|
||||
result.clear_with_capacity();
|
||||
TRY(result.try_append(item));
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-subresource-integrity/#does-response-match-metadatalist
|
||||
ErrorOr<bool> do_bytes_match_metadata_list(ByteBuffer const& bytes, StringView metadata_list)
|
||||
{
|
||||
// 1. Let parsedMetadata be the result of parsing metadataList.
|
||||
auto parsed_metadata = TRY(parse_metadata(metadata_list));
|
||||
|
||||
// 2. If parsedMetadata is empty set, return true.
|
||||
if (parsed_metadata.is_empty())
|
||||
return true;
|
||||
|
||||
// 3. Let metadata be the result of getting the strongest metadata from parsedMetadata.
|
||||
auto metadata = TRY(get_strongest_metadata_from_set(parsed_metadata));
|
||||
|
||||
// 4. For each item in metadata:
|
||||
for (auto const& item : metadata) {
|
||||
// 1. Let algorithm be the item["alg"].
|
||||
auto& algorithm = item.algorithm;
|
||||
|
||||
// 2. Let expectedValue be the item["val"].
|
||||
auto& expected_value = item.base64_value;
|
||||
|
||||
// 3. Let actualValue be the result of applying algorithm to bytes.
|
||||
auto actual_value = TRY(apply_algorithm_to_bytes(algorithm, bytes));
|
||||
|
||||
// 4. If actualValue is a case-sensitive match for expectedValue, return true.
|
||||
if (actual_value == expected_value)
|
||||
return true;
|
||||
}
|
||||
|
||||
// 5. Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue