github.com/prebid/prebid-server/v2@v2.18.0/gdpr/impl.go (about) 1 package gdpr 2 3 import ( 4 "context" 5 6 "github.com/prebid/go-gdpr/api" 7 "github.com/prebid/go-gdpr/consentconstants" 8 tcf2 "github.com/prebid/go-gdpr/vendorconsent/tcf2" 9 "github.com/prebid/prebid-server/v2/openrtb_ext" 10 ) 11 12 const noBidder openrtb_ext.BidderName = "" 13 14 // permissionsImpl contains global and request-specific GDPR config data and is used to determine 15 // whether various cookie sync and auction activities are permitted for a request 16 // permissionsImpl implements the Permissions interface 17 type permissionsImpl struct { 18 // global 19 fetchVendorList VendorListFetcher 20 gdprDefaultValue string 21 hostVendorID int 22 nonStandardPublishers map[string]struct{} 23 purposeEnforcerBuilder PurposeEnforcerBuilder 24 vendorIDs map[openrtb_ext.BidderName]uint16 25 // request-specific 26 aliasGVLIDs map[string]uint16 27 cfg TCF2ConfigReader 28 consent string 29 gdprSignal Signal 30 publisherID string 31 } 32 33 // HostCookiesAllowed determines whether the host is allowed to set cookies on the user's device 34 func (p *permissionsImpl) HostCookiesAllowed(ctx context.Context) (bool, error) { 35 if p.gdprSignal != SignalYes { 36 return true, nil 37 } 38 39 return p.allowSync(ctx, uint16(p.hostVendorID), noBidder, false) 40 } 41 42 // BidderSyncAllowed determines whether a given bidder is allowed to perform a cookie sync 43 func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.BidderName) (bool, error) { 44 if p.gdprSignal != SignalYes { 45 return true, nil 46 } 47 48 id, ok := p.vendorIDs[bidder] 49 if ok { 50 vendorExceptions := p.cfg.PurposeVendorExceptions(consentconstants.Purpose(1)) 51 _, vendorException := vendorExceptions[string(bidder)] 52 return p.allowSync(ctx, id, bidder, vendorException) 53 } 54 55 return false, nil 56 } 57 58 // AuctionActivitiesAllowed determines whether auction activities are permitted for a given bidder 59 func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions AuctionPermissions, err error) { 60 if _, ok := p.nonStandardPublishers[p.publisherID]; ok { 61 return AllowAll, nil 62 } 63 if p.gdprSignal != SignalYes { 64 return AllowAll, nil 65 } 66 if p.consent == "" { 67 return p.defaultPermissions(), nil 68 } 69 pc, err := parseConsent(p.consent) 70 if err != nil { 71 return p.defaultPermissions(), err 72 } 73 vendorID, _ := p.resolveVendorID(bidderCoreName, bidder) 74 vendor, err := p.getVendor(ctx, vendorID, *pc) 75 if err != nil { 76 return p.defaultPermissions(), err 77 } 78 vendorInfo := VendorInfo{vendorID: vendorID, vendor: vendor} 79 80 permissions = AuctionPermissions{} 81 permissions.AllowBidRequest = p.allowBidRequest(bidderCoreName, pc.consentMeta, vendorInfo) 82 permissions.PassGeo = p.allowGeo(bidderCoreName, pc.consentMeta, vendor) 83 permissions.PassID = p.allowID(bidderCoreName, pc.consentMeta, vendorInfo) 84 85 return permissions, nil 86 } 87 88 // defaultPermissions returns a permissions object that denies passing user IDs while 89 // allowing passing geo information and sending bid requests based on whether purpose 2 90 // and feature one are enforced respectively 91 // if the consent string is empty or malformed we should use the default permissions 92 func (p *permissionsImpl) defaultPermissions() AuctionPermissions { 93 perms := AuctionPermissions{} 94 95 if !p.cfg.PurposeEnforced(consentconstants.Purpose(2)) { 96 perms.AllowBidRequest = true 97 } 98 if !p.cfg.FeatureOneEnforced() { 99 perms.PassGeo = true 100 } 101 return perms 102 } 103 104 // resolveVendorID gets the vendor ID for the specified bidder from either the alias GVL IDs 105 // provided in the request or from the bidder configs loaded at startup 106 func (p *permissionsImpl) resolveVendorID(bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (id uint16, ok bool) { 107 if id, ok = p.aliasGVLIDs[string(bidder)]; ok { 108 return id, ok 109 } 110 111 id, ok = p.vendorIDs[bidderCoreName] 112 113 return id, ok 114 } 115 116 // allowSync computes cookie sync activity legal basis for a given bidder using the enforcement 117 // algorithms selected by the purpose enforcer builder 118 func (p *permissionsImpl) allowSync(ctx context.Context, vendorID uint16, bidder openrtb_ext.BidderName, vendorException bool) (bool, error) { 119 if p.consent == "" { 120 return false, nil 121 } 122 pc, err := parseConsent(p.consent) 123 if err != nil { 124 return false, err 125 } 126 vendor, err := p.getVendor(ctx, vendorID, *pc) 127 if err != nil { 128 return false, nil 129 } 130 vendorInfo := VendorInfo{vendorID: vendorID, vendor: vendor} 131 132 if !p.cfg.PurposeEnforced(consentconstants.Purpose(1)) { 133 return true, nil 134 } 135 136 if p.cfg.PurposeOneTreatmentEnabled() && pc.consentMeta.PurposeOneTreatment() { 137 return p.cfg.PurposeOneTreatmentAccessAllowed(), nil 138 } 139 140 purpose := consentconstants.Purpose(1) 141 enforcer := p.purposeEnforcerBuilder(purpose, string(bidder)) 142 143 if enforcer.LegalBasis(vendorInfo, string(bidder), pc.consentMeta, Overrides{blockVendorExceptions: !vendorException}) { 144 return true, nil 145 } 146 return false, nil 147 } 148 149 // allowBidRequest computes legal basis for a given bidder using the enforcement algorithms selected 150 // by the purpose enforcer builder 151 func (p *permissionsImpl) allowBidRequest(bidder openrtb_ext.BidderName, consentMeta tcf2.ConsentMetadata, vendorInfo VendorInfo) bool { 152 enforcer := p.purposeEnforcerBuilder(consentconstants.Purpose(2), string(bidder)) 153 154 overrides := Overrides{} 155 if _, ok := enforcer.(*BasicEnforcement); ok { 156 overrides.allowLITransparency = true 157 } 158 return enforcer.LegalBasis(vendorInfo, string(bidder), consentMeta, overrides) 159 } 160 161 // allowGeo computes legal basis for a given bidder using the configs, consent and GVL pertaining to 162 // feature one 163 func (p *permissionsImpl) allowGeo(bidder openrtb_ext.BidderName, consentMeta tcf2.ConsentMetadata, vendor api.Vendor) bool { 164 if !p.cfg.FeatureOneEnforced() { 165 return true 166 } 167 if p.cfg.FeatureOneVendorException(bidder) { 168 return true 169 } 170 171 basicEnforcementVendors := p.cfg.BasicEnforcementVendors() 172 _, weakVendorEnforcement := basicEnforcementVendors[string(bidder)] 173 return consentMeta.SpecialFeatureOptIn(1) && ((vendor != nil && vendor.SpecialFeature(1)) || weakVendorEnforcement) 174 } 175 176 // allowID computes the pass user ID activity legal basis for a given bidder using the enforcement algorithms 177 // selected by the purpose enforcer builder. For the user ID activity, the selected enforcement algorithm must 178 // always assume we are enforcing the purpose. 179 // If the purpose for which we are computing legal basis is purpose 2, the algorithm should allow LI transparency. 180 func (p *permissionsImpl) allowID(bidder openrtb_ext.BidderName, consentMeta tcf2.ConsentMetadata, vendorInfo VendorInfo) bool { 181 for i := 2; i <= 10; i++ { 182 purpose := consentconstants.Purpose(i) 183 enforcer := p.purposeEnforcerBuilder(purpose, string(bidder)) 184 185 overrides := Overrides{enforcePurpose: true, enforceVendors: true} 186 if _, ok := enforcer.(*BasicEnforcement); ok && purpose == consentconstants.Purpose(2) { 187 overrides.allowLITransparency = true 188 } 189 if enforcer.LegalBasis(vendorInfo, string(bidder), consentMeta, overrides) { 190 return true 191 } 192 } 193 194 return false 195 } 196 197 // getVendor retrieves the GVL vendor information for a particular bidder 198 func (p *permissionsImpl) getVendor(ctx context.Context, vendorID uint16, pc parsedConsent) (api.Vendor, error) { 199 vendorList, err := p.fetchVendorList(ctx, pc.specVersion, pc.listVersion) 200 if err != nil { 201 return nil, err 202 } 203 return vendorList.Vendor(vendorID), nil 204 } 205 206 // AllowHostCookies represents a GDPR permissions policy with host cookie syncing always allowed 207 type AllowHostCookies struct { 208 *permissionsImpl 209 } 210 211 // HostCookiesAllowed always returns true 212 func (p *AllowHostCookies) HostCookiesAllowed(ctx context.Context) (bool, error) { 213 return true, nil 214 } 215 216 // Exporting to allow for easy test setups 217 type AlwaysAllow struct{} 218 219 func (a AlwaysAllow) HostCookiesAllowed(ctx context.Context) (bool, error) { 220 return true, nil 221 } 222 func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.BidderName) (bool, error) { 223 return true, nil 224 } 225 func (a AlwaysAllow) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions AuctionPermissions, err error) { 226 return AllowAll, nil 227 }