blob: 3f3c6bd2946ee4382fde3a7e4bef10cc9ed578f3 [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_DOM_CSP_DELEGATE_H_
#define COBALT_DOM_CSP_DELEGATE_H_
#include <memory>
#include <string>
#include "cobalt/base/source_location.h"
#include "cobalt/csp/content_security_policy.h"
#include "cobalt/dom/csp_violation_reporter.h"
namespace cobalt {
namespace dom {
// Object that represents a Content Security Policy for a particular document.
// Owned by the Document. Objects wishing to enforce CSP need to query the
// delegate to decide if they are permitted to load a resource.
// Note that any thread may call CanLoad().
class CspDelegate {
public:
enum ResourceType {
kFont,
kImage,
kLocation,
kMedia,
kScript,
kStyle,
kXhr,
kWebSocket,
};
CspDelegate();
virtual ~CspDelegate();
// Return |true| if the given resource type can be loaded from |url|.
// Set |did_redirect| if url was the result of a redirect.
virtual bool CanLoad(ResourceType type, const GURL& url,
bool did_redirect) const = 0;
virtual bool IsValidNonce(ResourceType type,
const std::string& nonce) const = 0;
virtual bool AllowInline(ResourceType type,
const base::SourceLocation& location,
const std::string& script_content) const = 0;
// Return |true| if 'unsafe-eval' is set. No report will be generated in any
// case. If eval_disabled_message is non-NULL, it will be set with a message
// that should be reported when an application attempts to use eval().
virtual bool AllowEval(std::string* eval_disabled_message) const = 0;
// Report that code was generated from a string, such as through eval() or the
// Function constructor. If eval() is not allowed, generate a violation
// report. Otherwise if eval() is allowed this is a no-op.
virtual void ReportEval() const = 0;
// Signal to the CSP object that CSP policy directives have been received.
// Return |true| if success, |false| if failure and load should be aborted.
virtual bool OnReceiveHeaders(const csp::ResponseHeaders& headers) = 0;
virtual void OnReceiveHeader(const std::string& header,
csp::HeaderType header_type,
csp::HeaderSource header_source) = 0;
// Inform the policy that the document's origin has changed.
virtual void NotifyUrlChanged(const GURL& url) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CspDelegate);
};
// This class is just a no-op implementation that allows everything.
class CspDelegateInsecure : public CspDelegate {
public:
CspDelegateInsecure() {}
bool CanLoad(ResourceType, const GURL&, bool) const override { return true; }
bool IsValidNonce(ResourceType, const std::string&) const override {
return true;
}
bool AllowInline(ResourceType, const base::SourceLocation&,
const std::string&) const override {
return true;
}
bool AllowEval(std::string*) const override { return true; }
void ReportEval() const override {}
bool OnReceiveHeaders(const csp::ResponseHeaders&) override { return true; }
void OnReceiveHeader(const std::string&, csp::HeaderType,
csp::HeaderSource) override {}
void NotifyUrlChanged(const GURL&) const override {}
private:
DISALLOW_COPY_AND_ASSIGN(CspDelegateInsecure);
};
class CspDelegateSecure : public CspDelegate {
public:
CspDelegateSecure(std::unique_ptr<CspViolationReporter> violation_reporter,
const GURL& url, csp::CSPHeaderPolicy require_csp,
const base::Closure& policy_changed_callback);
~CspDelegateSecure();
// Return |true| if the given resource type can be loaded from |url|.
// Set |did_redirect| if url was the result of a redirect.
bool CanLoad(ResourceType type, const GURL& url,
bool did_redirect) const override;
bool IsValidNonce(ResourceType type, const std::string& nonce) const override;
bool AllowInline(ResourceType type, const base::SourceLocation& location,
const std::string& script_content) const override;
// Return |true| if 'unsafe-eval' is set. No report will be generated in any
// case. If eval_disabled_message is non-NULL, it will be set with a message
// that should be reported when an application attempts to use eval().
bool AllowEval(std::string* eval_disabled_message) const override;
// Report that code was generated from a string, such as through eval() or the
// Function constructor. If eval() is not allowed, generate a violation
// report. Otherwise if eval() is allowed this is a no-op.
void ReportEval() const override;
// Signal to the CSP object that CSP policy directives have been received.
// Return |true| if success, |false| if failure and load should be aborted.
bool OnReceiveHeaders(const csp::ResponseHeaders& headers) override;
void OnReceiveHeader(const std::string& header, csp::HeaderType header_type,
csp::HeaderSource header_source) override;
void NotifyUrlChanged(const GURL& url) const override {
return csp_->NotifyUrlChanged(url);
}
protected:
void SetLocationPolicy(const std::string& policy);
std::unique_ptr<csp::ContentSecurityPolicy> csp_;
// Helper class to send violation events to any reporting endpoints.
std::unique_ptr<CspViolationReporter> reporter_;
// We disallow all loads if CSP headers weren't received. This tracks if we
// did get a valid header.
bool was_header_received_;
// This should be called any time the CSP policy changes. For example, after
// receiving (and parsing) the headers, or after encountering a CSP directive
// in a <meta> tag.
base::Closure policy_changed_callback_;
// Whether Cobalt is forbidden to render without receiving CSP header.
csp::CSPHeaderPolicy require_csp_;
private:
DISALLOW_COPY_AND_ASSIGN(CspDelegateSecure);
};
} // namespace dom
} // namespace cobalt
#endif // COBALT_DOM_CSP_DELEGATE_H_