github.com/google/go-safeweb@v0.0.0-20231219055052-64d8cfc90fbb/safehttp/plugins/coop/coop.go (about) 1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package coop provides Cross-Origin-Opener-Policy protection. Specification: https://html.spec.whatwg.org/#cross-origin-opener-policies 16 package coop 17 18 import ( 19 "github.com/google/go-safeweb/safehttp" 20 ) 21 22 var _ safehttp.Interceptor = Interceptor{} 23 24 // Mode represents a COOP mode. 25 type Mode string 26 27 const ( 28 // SameOrigin is the strictest and safest COOP available: windows can keep a reference of windows they open only if they are same-origin. 29 SameOrigin Mode = "same-origin" 30 // SameOriginAllowPopups relaxes the same-origin COOP: windows on this origin that open other windows are allowed to keep a reference, but the opposite is not valid. 31 SameOriginAllowPopups Mode = "same-origin-allow-popups" 32 // UnsafeNone disables COOP: this is the default value in browsers. 33 UnsafeNone Mode = "unsafe-none" 34 ) 35 36 // Policy represents a Cross-Origin-Opener-Policy value. 37 type Policy struct { 38 // Mode is the mode for the policy. 39 Mode Mode 40 // ReportingGroup is an optional reporting group that needs to be defined with the Reporting API. 41 ReportingGroup string 42 // ReportOnly makes the policy report-only if set. 43 ReportOnly bool 44 } 45 46 // String serializes the policy. The returned value can be used as a header value. 47 func (p Policy) String() string { 48 if p.ReportingGroup == "" { 49 return string(p.Mode) 50 } 51 return string(p.Mode) + `; report-to "` + p.ReportingGroup + `"` 52 } 53 54 type serializedPolicies struct { 55 rep []string 56 enf []string 57 } 58 59 func serializePolicies(policies ...Policy) serializedPolicies { 60 var s serializedPolicies 61 for _, p := range policies { 62 if p.ReportOnly { 63 s.rep = append(s.rep, p.String()) 64 } else { 65 s.enf = append(s.enf, p.String()) 66 } 67 } 68 return s 69 } 70 71 // NewInterceptor constructs an interceptor that applies the given policies. 72 func NewInterceptor(policies ...Policy) Interceptor { 73 return Interceptor(serializePolicies(policies...)) 74 } 75 76 // Default returns a same-origin enforcing interceptor with the given (potentially empty) report group. 77 func Default(reportGroup string) Interceptor { 78 return NewInterceptor(Policy{Mode: SameOrigin, ReportingGroup: reportGroup}) 79 } 80 81 // Interceptor is the interceptor for COOP. 82 type Interceptor serializedPolicies 83 84 // Before claims and sets the Report-Only and Enforcement headers for COOP. 85 func (it Interceptor) Before(w safehttp.ResponseWriter, r *safehttp.IncomingRequest, cfg safehttp.InterceptorConfig) safehttp.Result { 86 if cfg != nil { 87 // We got an override, run its Before phase instead. 88 return Interceptor(cfg.(Overrider)).Before(w, r, nil) 89 } 90 w.Header().Claim("Cross-Origin-Opener-Policy")(it.enf) 91 w.Header().Claim("Cross-Origin-Opener-Policy-Report-Only")(it.rep) 92 return safehttp.NotWritten() 93 } 94 95 // Commit is a no-op, required to satisfy the safehttp.Interceptor interface. 96 func (it Interceptor) Commit(w safehttp.ResponseHeadersWriter, r *safehttp.IncomingRequest, resp safehttp.Response, _ safehttp.InterceptorConfig) { 97 } 98 99 // Match recognizes Overriders as COOP configurations. 100 func (it Interceptor) Match(cfg safehttp.InterceptorConfig) bool { 101 _, ok := cfg.(Overrider) 102 return ok 103 } 104 105 // Overrider is a safehttp.InterceptorConfig that allows to override COOP for a specific handler. 106 type Overrider serializedPolicies 107 108 // Override creates an Overrider with the given policies. 109 func Override(reason string, policies ...Policy) Overrider { 110 return Overrider(serializePolicies(policies...)) 111 }