libreoffice-online/wsd/ContentSecurityPolicy.hpp
Michael Meeks 0e8d674617 Trim URIs if necessary, and test that.
Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
Change-Id: I4f8cef1fb05a6f8fa8f85010adbf8b0ccd8af9e9
2024-07-11 12:52:30 +01:00

94 lines
2.8 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* Copyright the Collabora Online contributors.
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "Log.hpp"
#include "StringVector.hpp"
#include "Util.hpp"
#include <sstream>
#include <string>
#include <unordered_map>
/// Manages the HTTP Content-Security-Policy Header.
/// See https://www.w3.org/TR/CSP2/
class ContentSecurityPolicy
{
public:
ContentSecurityPolicy() = default;
ContentSecurityPolicy(const ContentSecurityPolicy& other)
: _directives(other._directives)
{
}
/// Given a CSP string, merge it with the existing values.
void merge(const std::string& csp)
{
LOG_TRC("Merging CSP directives [" << csp << ']');
StringVector tokens = StringVector::tokenize(csp, ';');
for (std::size_t i = 0; i < tokens.size(); ++i)
{
const std::string token = Util::trimmed(tokens[i]);
if (!token.empty())
{
LOG_TRC("Merging CSP directive [" << token << ']');
const auto parts = Util::split(token);
appendDirective(parts.first, parts.second);
}
}
}
/// Append the given URL to a directive.
/// @value must be space-delimited and cannot have semicolon.
void appendDirectiveUrl(std::string directive, std::string url)
{
appendDirective(directive, Util::trimURI(url));
}
/// Append the given value to a directive.
/// @value must be space-delimited and cannot have semicolon.
void appendDirective(std::string directive, std::string value)
{
if (value.find_first_of(';') != std::string::npos)
{
LOG_WRN("Unexpected semicolon in CSP source [" << value << "] for policy directive ["
<< directive << "] - ignoring it.");
return;
}
Util::trim(directive);
Util::trim(value);
if (!directive.empty() && !value.empty())
{
LOG_TRC("Appending CSP directive [" << directive << "] = [" << value << ']');
_directives[directive].append(' ' + value);
}
}
/// Returns the value of the CSP header.
std::string generate() const
{
std::ostringstream oss;
for (const auto& pair : _directives)
{
oss << pair.first << ' ' << pair.second << "; ";
}
return oss.str();
}
private:
/// The policy directives.
std::unordered_map<std::string, std::string> _directives;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */