iab_consent_string 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/iab_consent_string.rb +14 -0
- data/lib/iab_consent_string/bits.rb +207 -0
- data/lib/iab_consent_string/consent/implementation/v1/byte_buffer_backed_vendor_consent.rb +162 -0
- data/lib/iab_consent_string/consent/implementation/v1/vendor_consent_builder.rb +246 -0
- data/lib/iab_consent_string/consent/range/range_entry.rb +22 -0
- data/lib/iab_consent_string/consent/range/single_range_entry.rb +33 -0
- data/lib/iab_consent_string/consent/range/start_end_range_entry.rb +36 -0
- data/lib/iab_consent_string/consent/vendor_consent.rb +91 -0
- data/lib/iab_consent_string/consent/vendor_consent_decoder.rb +41 -0
- data/lib/iab_consent_string/consent/vendor_consent_encoder.rb +15 -0
- data/lib/iab_consent_string/error/vendor_consent_create_error.rb +8 -0
- data/lib/iab_consent_string/error/vendor_consent_error.rb +6 -0
- data/lib/iab_consent_string/error/vendor_consent_parse_error.rb +8 -0
- data/lib/iab_consent_string/gdpr_constants.rb +33 -0
- data/lib/iab_consent_string/purpose.rb +69 -0
- data/lib/iab_consent_string/util/utils.rb +28 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 603e1f8a6c7839dd0206dac21322c64bf3199f8b
|
4
|
+
data.tar.gz: 28349c00d6545617eadd88b4cab1b3f815649129
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 60525c45d3349de4d745ff1f70427d6fc5e83fc641b0d752d08e8af43410126eba278446769dcc8178bdca906657f54ade477da19c0c42e4d591600ec7283b30
|
7
|
+
data.tar.gz: 1aa2736692465a5b053d876be1e7751713a3206111d3a3f96f7c1d49835b3bfefe83eb18d81950ae30354666521f7b25661833e528f0ac4cdfdeb27c3ca890b3
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'iab_consent_string/consent/vendor_consent'
|
2
|
+
require 'iab_consent_string/consent/vendor_consent_encoder'
|
3
|
+
require 'iab_consent_string/consent/vendor_consent_decoder'
|
4
|
+
require 'iab_consent_string/consent/implementation/v1/byte_buffer_backed_vendor_consent'
|
5
|
+
require 'iab_consent_string/consent/implementation/v1/vendor_consent_builder'
|
6
|
+
require 'iab_consent_string/consent/range/range_entry.rb'
|
7
|
+
require 'iab_consent_string/consent/range/start_end_range_entry.rb'
|
8
|
+
require 'iab_consent_string/consent/range/single_range_entry.rb'
|
9
|
+
require 'iab_consent_string/gdpr_constants'
|
10
|
+
require 'iab_consent_string/purpose'
|
11
|
+
require 'iab_consent_string/util/utils'
|
12
|
+
|
13
|
+
module IABConsentString
|
14
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'iab_consent_string/error/vendor_consent_create_error'
|
2
|
+
require 'iab_consent_string/error/vendor_consent_parse_error'
|
3
|
+
|
4
|
+
# @author Fidzup Coding Stars Team
|
5
|
+
module IABConsentString
|
6
|
+
class Bits
|
7
|
+
# big endian
|
8
|
+
BYTE_POWS = [ -128, 64, 32, 16, 8, 4, 2, 1 ]
|
9
|
+
|
10
|
+
def initialize(b)
|
11
|
+
@bytes = b
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get the value of the specified index bit, under a boolean format (1 = true, 0 = false)
|
15
|
+
# @param index [Integer] the nth number bit to get from the bit string
|
16
|
+
# @return [Boolean], true if the bit is switched to 1, false otherwise
|
17
|
+
def getBit(index)
|
18
|
+
byteIndex = index / 8
|
19
|
+
bitExact = index % 8
|
20
|
+
b = @bytes[byteIndex]
|
21
|
+
return (b & BYTE_POWS[bitExact]) != 0
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set the value of the specified index bit to 1
|
25
|
+
# @param index [Integer] set the nth number bit from the bit string
|
26
|
+
def setBit(index)
|
27
|
+
byteIndex = index / 8
|
28
|
+
shift = (byteIndex + 1) * 8 - index - 1
|
29
|
+
@bytes[byteIndex] |= 1 << shift
|
30
|
+
end
|
31
|
+
|
32
|
+
# Set the value of the specified index bit to 1
|
33
|
+
# @param index [Integer] set the nth number bit from the bit string
|
34
|
+
def unsetBit(index)
|
35
|
+
byteIndex = index / 8
|
36
|
+
shift = (byteIndex + 1) * 8 - index - 1
|
37
|
+
@bytes[byteIndex] &= ~(1 << shift)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Interprets n number of bits as a big endiant int
|
41
|
+
# @param startInclusive [Integer] the nth to begin interpreting from
|
42
|
+
# @param size [Integer] the number of bits to interpret
|
43
|
+
# @return [void]
|
44
|
+
# @raise [VendorConsentParseError] when the bits cannot fit in an int sized field
|
45
|
+
def getInt(startInclusive, size)
|
46
|
+
# Integer Size limited to 32 bits
|
47
|
+
if (size > 32)
|
48
|
+
raise IABConsentString::Error::VendorConsentParseError, "can't fit bit range in int " + size, caller
|
49
|
+
end
|
50
|
+
val = 0
|
51
|
+
sigMask = 1
|
52
|
+
sigIndex = size - 1
|
53
|
+
|
54
|
+
for i in (0...size) do
|
55
|
+
if getBit(startInclusive + i)
|
56
|
+
val += (sigMask << sigIndex)
|
57
|
+
end
|
58
|
+
sigIndex -= 1
|
59
|
+
end
|
60
|
+
val
|
61
|
+
end
|
62
|
+
|
63
|
+
# Writes an integer value into a bit array of given size
|
64
|
+
# @param startInclusive [Integer] the nth to begin writing to
|
65
|
+
# @param size [Integer] the number of bits available to write
|
66
|
+
# @param to [Integer] the integer to write out
|
67
|
+
# @return [void]
|
68
|
+
# @raise [VendorConsentCreateError] when the bits cannot fit into the provided size
|
69
|
+
def setInt(startInclusive, size, to)
|
70
|
+
# Integer Size limited to 32 bits
|
71
|
+
if (size > 32 || to > maxOfSize(size) || to < 0)
|
72
|
+
raise IABConsentString::Error::VendorConsentCreateError, "can't fit integer into bit range of size" + size , caller
|
73
|
+
end
|
74
|
+
|
75
|
+
setNumber(startInclusive, size, to);
|
76
|
+
end
|
77
|
+
|
78
|
+
# Interprets n bits as a big endian long
|
79
|
+
# @param startInclusive [Integer] the nth to begin interpreting from
|
80
|
+
# @param size [Integer] the number of bits to interpret
|
81
|
+
# @return [Long] the long value create by interpretation of provided bits
|
82
|
+
# @raise [VendorConsentParseError] when the bits cannot fit in a long sized field
|
83
|
+
def getLong(startInclusive, size)
|
84
|
+
# Long Size limited to 64 bits
|
85
|
+
if (size > 64)
|
86
|
+
raise IABConsentString::Error::VendorConsentParseError, "can't fit bit range in long: " + size , caller
|
87
|
+
end
|
88
|
+
val = 0
|
89
|
+
sigMask = 1
|
90
|
+
sigIndex = size - 1
|
91
|
+
|
92
|
+
for i in (0...size) do
|
93
|
+
if (getBit(startInclusive + i))
|
94
|
+
val += (sigMask << sigIndex)
|
95
|
+
end
|
96
|
+
sigIndex -= 1
|
97
|
+
end
|
98
|
+
val
|
99
|
+
end
|
100
|
+
|
101
|
+
# Writes a long value into a bit array of given size
|
102
|
+
# @param startInclusive [Integer] the nth to begin writing to
|
103
|
+
# @param size [Integer] the number of bits available to write
|
104
|
+
# @param to [Integer] the long number to write out
|
105
|
+
# @return [void]
|
106
|
+
# @raise [VendorConsentCreateError] when the bits cannot fit into the provided size
|
107
|
+
def setLong(startInclusive, size, to)
|
108
|
+
# Long Size limited to 64 bits
|
109
|
+
if (size > 64 || to > maxOfSize(size) || to < 0)
|
110
|
+
raise IABConsentString::Error::VendorConsentCreateError, "can't fit long into bit range of size " + size , caller
|
111
|
+
end
|
112
|
+
|
113
|
+
setNumber(startInclusive, size, to)
|
114
|
+
end
|
115
|
+
|
116
|
+
# returns a time derived from interpreting the given interval on the bit string as long representing
|
117
|
+
# the number of demiseconds from the unix epoch
|
118
|
+
# @param startInclusive [Integer] the bit from which to begin interpreting
|
119
|
+
# @param size [Integer] the number of bits to interpret
|
120
|
+
# @return [void]
|
121
|
+
# @raise [VendorConsentParseError] when the number of bits requested cannot fit in a long
|
122
|
+
def getDateTimeFromEpochDeciseconds(startInclusive,size)
|
123
|
+
epochDemi = getLong(startInclusive, size)
|
124
|
+
epochDemi * 100
|
125
|
+
end
|
126
|
+
|
127
|
+
def setDateTimeToEpochDeciseconds(startInclusive, size, dateTime)
|
128
|
+
setLong(startInclusive, size, dateTime / 100)
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return [Integer] the number of bits in the bit string
|
132
|
+
def length
|
133
|
+
@bytes.length * 8
|
134
|
+
end
|
135
|
+
|
136
|
+
# Interprets the given interval in the bit string as a series of six bit characters, where 0=A and 26=Z
|
137
|
+
# @param startInclusive [Integer] the nth bit in the bitstring from which to start the interpretation
|
138
|
+
# @param size [Integer] the number of bits to include in the string
|
139
|
+
# @return [String] the string given by the above interpretation
|
140
|
+
# @raise [VendorConsentParseError] when the requested interval is not a multiple of six
|
141
|
+
def getSixBitString(startInclusive, size)
|
142
|
+
if (size % 6 != 0)
|
143
|
+
raise IABConsentString::Error::VendorConsentParseError , "string bit length must be multiple of six: " + size, caller
|
144
|
+
end
|
145
|
+
charNum = size / 6
|
146
|
+
val = String.new()
|
147
|
+
for i in (0...charNum) do
|
148
|
+
charCode = getInt(startInclusive + (i * 6), 6) + 65
|
149
|
+
val << charCode.chr
|
150
|
+
end
|
151
|
+
val.upcase
|
152
|
+
end
|
153
|
+
|
154
|
+
# Interprets characters, as 0=A and 26=Z and writes to the given interval in the bit string as a series of six bits
|
155
|
+
# @param startInclusive [Integer] the nth bit in the bitstring from which to start writing
|
156
|
+
# @param size [Integer] the size of the bitstring
|
157
|
+
# @param to [Integer] the string given by the above interpretation
|
158
|
+
# @raise [VendorConsentCreateError] when the requested interval is not a multiple of six
|
159
|
+
def setSixBitString(startInclusive, size, to)
|
160
|
+
if (size % 6 != 0 || size / 6 != to.length())
|
161
|
+
raise IABConsentString::Error::VendorConsentCreateError , "bit array size must be multiple of six and equal to 6 times the size of string", caller
|
162
|
+
end
|
163
|
+
values = to.chars
|
164
|
+
for i in (0...values.length) do
|
165
|
+
charCode = values[i].ord - 65
|
166
|
+
setInt(startInclusive + (i * 6), 6, charCode)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# @return [String] a string representation of the byte array passed in the constructor. for example, a bit array of [4]
|
171
|
+
# yields a String of "0100"
|
172
|
+
def getBinaryString
|
173
|
+
s = String.new()
|
174
|
+
size = length()
|
175
|
+
for i in (0...size) do
|
176
|
+
if (getBit(i))
|
177
|
+
s << "1"
|
178
|
+
else
|
179
|
+
s << "0"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
s
|
183
|
+
end
|
184
|
+
|
185
|
+
def toByteArray
|
186
|
+
@bytes
|
187
|
+
end
|
188
|
+
|
189
|
+
def setNumber(startInclusive,size,to)
|
190
|
+
(size - 1).downto(0) do |i|
|
191
|
+
index = startInclusive + i
|
192
|
+
byteIndex = index / 8
|
193
|
+
shift = (byteIndex + 1) * 8 - index - 1
|
194
|
+
@bytes[byteIndex] |= (to % 2) << shift
|
195
|
+
to /= 2
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def maxOfSize(size)
|
200
|
+
max = 0
|
201
|
+
for i in (0...size) do
|
202
|
+
max += 2**i
|
203
|
+
end
|
204
|
+
max
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'date'
|
3
|
+
require 'iab_consent_string/bits'
|
4
|
+
require 'iab_consent_string/gdpr_constants'
|
5
|
+
require 'iab_consent_string/consent/vendor_consent'
|
6
|
+
|
7
|
+
module IABConsentString
|
8
|
+
module Consent
|
9
|
+
module Implementation
|
10
|
+
module V1
|
11
|
+
class ByteBufferBackedVendorConsent < IABConsentString::Consent::VendorConsent
|
12
|
+
def initialize(bits)
|
13
|
+
@bits = bits
|
14
|
+
end
|
15
|
+
|
16
|
+
def getVersion
|
17
|
+
@bits.getInt(IABConsentString::GDPRConstants::VERSION_BIT_OFFSET,IABConsentString::GDPRConstants::VERSION_BIT_SIZE)
|
18
|
+
end
|
19
|
+
|
20
|
+
def getConsentRecordCreated
|
21
|
+
@bits.getDateTimeFromEpochDeciseconds(IABConsentString::GDPRConstants::CREATED_BIT_OFFSET, IABConsentString::GDPRConstants::CREATED_BIT_SIZE)
|
22
|
+
end
|
23
|
+
|
24
|
+
def getConsentRecordLastUpdated
|
25
|
+
@bits.getDateTimeFromEpochDeciseconds(IABConsentString::GDPRConstants::UPDATED_BIT_OFFSET,IABConsentString::GDPRConstants::UPDATED_BIT_SIZE)
|
26
|
+
end
|
27
|
+
|
28
|
+
def getCmpId
|
29
|
+
@bits.getInt(IABConsentString::GDPRConstants::CMP_ID_OFFSET,IABConsentString::GDPRConstants::CMP_ID_SIZE)
|
30
|
+
end
|
31
|
+
|
32
|
+
def getCmpVersion
|
33
|
+
@bits.getInt(IABConsentString::GDPRConstants::CMP_VERSION_OFFSET,IABConsentString::GDPRConstants::CMP_VERSION_SIZE)
|
34
|
+
end
|
35
|
+
|
36
|
+
def getConsentScreen
|
37
|
+
@bits.getInt(IABConsentString::GDPRConstants::CONSENT_SCREEN_SIZE_OFFSET,IABConsentString::GDPRConstants::CONSENT_SCREEN_SIZE)
|
38
|
+
end
|
39
|
+
|
40
|
+
def getConsentLanguage
|
41
|
+
@bits.getSixBitString(IABConsentString::GDPRConstants::CONSENT_LANGUAGE_OFFSET,IABConsentString::GDPRConstants::CONSENT_LANGUAGE_SIZE)
|
42
|
+
end
|
43
|
+
|
44
|
+
def getVendorListVersion
|
45
|
+
@bits.getInt(IABConsentString::GDPRConstants::VENDOR_LIST_VERSION_OFFSET,IABConsentString::GDPRConstants::VENDOR_LIST_VERSION_SIZE)
|
46
|
+
end
|
47
|
+
|
48
|
+
def getAllowedPurposeIds
|
49
|
+
allowedPurposes = Set[]
|
50
|
+
for i in (IABConsentString::GDPRConstants::PURPOSES_OFFSET...(IABConsentString::GDPRConstants::PURPOSES_OFFSET + IABConsentString::GDPRConstants::PURPOSES_SIZE)) do
|
51
|
+
if (@bits.getBit(i))
|
52
|
+
allowedPurposes.add(i - IABConsentString::GDPRConstants::PURPOSES_OFFSET + 1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
allowedPurposes
|
56
|
+
end
|
57
|
+
|
58
|
+
def getAllowedPurposes
|
59
|
+
allowedPurposes = getAllowedPurposeIds().map! {|id| IABConsentString::Purpose.new(id)}
|
60
|
+
allowedPurposes.to_a.uniq{|o| [o.getId]}.to_set
|
61
|
+
end
|
62
|
+
|
63
|
+
def getAllowedPurposesBits
|
64
|
+
@bits.getInt(IABConsentString::GDPRConstants::PURPOSES_OFFSET,IABConsentString::GDPRConstants::PURPOSES_SIZE)
|
65
|
+
end
|
66
|
+
|
67
|
+
def getMaxVendorId
|
68
|
+
@bits.getInt(IABConsentString::GDPRConstants::MAX_VENDOR_ID_OFFSET,IABConsentString::GDPRConstants::MAX_VENDOR_ID_SIZE)
|
69
|
+
end
|
70
|
+
|
71
|
+
def isPurposeIdAllowed(purposeId)
|
72
|
+
if ((purposeId < 1) || (purposeId > IABConsentString::GDPRConstants::PURPOSES_SIZE))
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
@bits.getBit(IABConsentString::GDPRConstants::PURPOSES_OFFSET + purposeId - 1);
|
76
|
+
end
|
77
|
+
|
78
|
+
def isPurposeAllowed(purpose)
|
79
|
+
isPurposeIdAllowed(purpose.getId())
|
80
|
+
end
|
81
|
+
|
82
|
+
def isVendorAllowed(vendorId)
|
83
|
+
if ((vendorId < 1) || (vendorId > getMaxVendorId()))
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
if (encodingType() == IABConsentString::GDPRConstants::VENDOR_ENCODING_RANGE)
|
87
|
+
defaultConsent = @bits.getBit(IABConsentString::GDPRConstants::DEFAULT_CONSENT_OFFSET)
|
88
|
+
present = isVendorPresentInRange(vendorId)
|
89
|
+
return (present != defaultConsent)
|
90
|
+
else
|
91
|
+
return @bits.getBit(IABConsentString::GDPRConstants::VENDOR_BITFIELD_OFFSET + vendorId - 1)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def toByteArray
|
96
|
+
@bits.toByteArray()
|
97
|
+
end
|
98
|
+
|
99
|
+
def hashCode
|
100
|
+
@bit.toByteArray().toString().hash
|
101
|
+
end
|
102
|
+
|
103
|
+
def toString
|
104
|
+
"ByteBufferVendorConsent{" +
|
105
|
+
"Version=" + getVersion().to_s +
|
106
|
+
",Created=" + getConsentRecordCreated().to_s +
|
107
|
+
",LastUpdated=" + getConsentRecordLastUpdated().to_s +
|
108
|
+
",CmpId=" + getCmpId().to_s +
|
109
|
+
",CmpVersion=" + getCmpVersion().to_s +
|
110
|
+
",ConsentScreen=" + getConsentScreen().to_s +
|
111
|
+
",ConsentLanguage=" + getConsentLanguage() +
|
112
|
+
",VendorListVersion=" + getVendorListVersion().to_s +
|
113
|
+
",PurposesAllowed=" + getAllowedPurposeIds().to_s +
|
114
|
+
",MaxVendorId=" + getMaxVendorId().to_s +
|
115
|
+
",EncodingType=" + encodingType().to_s +
|
116
|
+
"}"
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def encodingType
|
121
|
+
@bits.getInt(IABConsentString::GDPRConstants::ENCODING_TYPE_OFFSET, IABConsentString::GDPRConstants::ENCODING_TYPE_SIZE)
|
122
|
+
end
|
123
|
+
|
124
|
+
def isVendorPresentInRange(vendorId)
|
125
|
+
numEntries = @bits.getInt(IABConsentString::GDPRConstants::NUM_ENTRIES_OFFSET, IABConsentString::GDPRConstants::NUM_ENTRIES_SIZE)
|
126
|
+
maxVendorId = getMaxVendorId()
|
127
|
+
currentOffset = IABConsentString::GDPRConstants::RANGE_ENTRY_OFFSET
|
128
|
+
for i in (0...numEntries) do
|
129
|
+
range = @bits.getBit(currentOffset)
|
130
|
+
currentOffset += 1
|
131
|
+
if range
|
132
|
+
startVendorId = @bits.getInt(currentOffset, IABConsentString::GDPRConstants::VENDOR_ID_SIZE)
|
133
|
+
currentOffset += IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
134
|
+
endVendorId = @bits.getInt(currentOffset, IABConsentString::GDPRConstants::VENDOR_ID_SIZE)
|
135
|
+
currentOffset += IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
136
|
+
|
137
|
+
if ((startVendorId > endVendorId) || (endVendorId > maxVendorId))
|
138
|
+
raise IABConsentString::Error::VendorConsentParseError.new("Start VendorId must not be greater than End VendorId and End VendorId must not be greater than Max Vendor Id")
|
139
|
+
end
|
140
|
+
if ((vendorId >= startVendorId) && (vendorId <= endVendorId))
|
141
|
+
return true
|
142
|
+
end
|
143
|
+
else
|
144
|
+
singleVendorId = @bits.getInt(currentOffset, IABConsentString::GDPRConstants::VENDOR_ID_SIZE)
|
145
|
+
currentOffset += IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
146
|
+
|
147
|
+
if (singleVendorId > maxVendorId)
|
148
|
+
raise IABConsentString::Error::VendorConsentParseError.new("VendorId in the range entries must not be greater than Max VendorId")
|
149
|
+
end
|
150
|
+
if (singleVendorId == vendorId)
|
151
|
+
return true
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'iab_consent_string/gdpr_constants'
|
2
|
+
require 'iab_consent_string/error/vendor_consent_create_error'
|
3
|
+
require 'iab_consent_string/consent/implementation/v1/byte_buffer_backed_vendor_consent'
|
4
|
+
|
5
|
+
module IABConsentString
|
6
|
+
module Consent
|
7
|
+
module Implementation
|
8
|
+
module V1
|
9
|
+
# Builder for version 1 of vendor consent
|
10
|
+
class VendorConsentBuilder
|
11
|
+
VERSION = 1
|
12
|
+
|
13
|
+
# With creation date
|
14
|
+
# @param consentRecordCreated [DateTime] Epoch deciseconds when record was created
|
15
|
+
# @return [VendorConsentBuilder] self
|
16
|
+
def withConsentRecordCreatedOn(consentRecordCreated)
|
17
|
+
@consentRecordCreated = consentRecordCreated
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
# With update date
|
22
|
+
# @param consentRecordLastUpdated [DateTime] Epoch deciseconds when consent string was last updated
|
23
|
+
# @return [VendorConsentBuilder] self
|
24
|
+
def withConsentRecordLastUpdatedOn(consentRecordLastUpdated)
|
25
|
+
@consentRecordLastUpdated = consentRecordLastUpdated;
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# With CMP version
|
30
|
+
# @param cmpVersion [Integer] Consent Manager Provider version
|
31
|
+
# @return [VendorConsentBuilder] self
|
32
|
+
def withCmpVersion(cmpVersion)
|
33
|
+
@cmpVersion = cmpVersion
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# With CMP Id
|
38
|
+
# @param cmpId [Integer] Consent Manager Provider Id
|
39
|
+
# @return [VendorConsentBuilder] self
|
40
|
+
def withCmpId(cmpId)
|
41
|
+
@cmpId = cmpId
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
# With Consent Screen Id
|
46
|
+
# @param consentScreenId [Integer] Consent Screen Id
|
47
|
+
# @return [VendorConsentBuilder] self
|
48
|
+
def withConsentScreenId(consentScreenId)
|
49
|
+
@consentScreenId = consentScreenId
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# With consent language
|
54
|
+
# @param consentLanguage [Char(2)] Two-letter ISO639-1 language code that CMP asked for consent in
|
55
|
+
# @return [VendorConsentBuilder] self
|
56
|
+
def withConsentLanguage(consentLanguage)
|
57
|
+
@consentLanguage = consentLanguage
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# With vendor list version
|
62
|
+
# @param vendorListVersion [Integer] Version of vendor list used in most recent consent string update
|
63
|
+
# @return [VendorConsentBuilder] self
|
64
|
+
def withVendorListVersion(vendorListVersion)
|
65
|
+
@vendorListVersion = vendorListVersion
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# With allowed purpose IDs
|
70
|
+
# @param allowedPurposeIds [Set<Integer>] set of allowed purposes
|
71
|
+
# @return [VendorConsentBuilder] self
|
72
|
+
def withAllowedPurposeIds(allowedPurposeIds)
|
73
|
+
if allowedPurposeIds.nil?
|
74
|
+
raise "Argument allowedPurposeIds is null"
|
75
|
+
end
|
76
|
+
allowedPurposeIds.each do |purposeId|
|
77
|
+
if purposeId < 0 || purposeId > IABConsentString::GDPRConstants::PURPOSES_SIZE
|
78
|
+
raise "Invalid purpose ID found"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@allowedPurposes = allowedPurposeIds;
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
# With allowed purposes
|
86
|
+
# @param allowedPurposes [Set<Purpose>] set of allowed purposes
|
87
|
+
# @return [VendorConsentBuilder] self
|
88
|
+
def withAllowedPurposes(allowedPurposes)
|
89
|
+
if allowedPurposes.nil?
|
90
|
+
raise "Argument allowedPurposes is null"
|
91
|
+
end
|
92
|
+
@allowedPurposes = allowedPurposes.map! {|purpose| purpose.getId }
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
# With max vendor ID
|
97
|
+
# @param maxVendorId [Integer] The maximum VendorId for which consent values are given.
|
98
|
+
# @return [VendorConsentBuilder] self
|
99
|
+
def withMaxVendorId(maxVendorId)
|
100
|
+
@maxVendorId = maxVendorId
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# With vendor encoding type
|
105
|
+
# @param vendorEncodingType [Integer] 0=BitField 1=Range
|
106
|
+
# @return [VendorConsentBuilder] self
|
107
|
+
def withVendorEncodingType(vendorEncodingType)
|
108
|
+
if (vendorEncodingType < 0 || vendorEncodingType > 1)
|
109
|
+
raise "Illegal value for argument vendorEncodingType:" + vendorEncodingType.to_s
|
110
|
+
end
|
111
|
+
@vendorEncodingType = vendorEncodingType
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
# With bit field entries
|
116
|
+
# @param bitFieldEntries [Set<Integer>] set of VendorIds for which the vendors have consent
|
117
|
+
# @return [VendorConsentBuilder] self
|
118
|
+
def withBitField(bitFieldEntries)
|
119
|
+
@vendorsBitField = bitFieldEntries
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
# With range entries
|
124
|
+
# @param rangeEntries [Set<RangeEntry>] List of VendorIds or a range of VendorIds for which the vendors have consent
|
125
|
+
# @return [VendorConsentBuilder] self
|
126
|
+
def withRangeEntries(rangeEntries)
|
127
|
+
@rangeEntries = rangeEntries
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
# With default consent
|
132
|
+
# @param defaultConsent [Boolean] Default consent for VendorIds not covered by a RangeEntry. 0=No Consent 1=Consent
|
133
|
+
# @return [VendorConsentBuilder] self
|
134
|
+
def withDefaultConsent(defaultConsent)
|
135
|
+
@defaultConsent = defaultConsent
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
# Validate supplied values and build VendorConsent object
|
140
|
+
# @return [IABConsentString::Consent::VendorConsent] vendor consent object
|
141
|
+
def build
|
142
|
+
if @consentRecordCreated.nil?
|
143
|
+
raise IABConsentString::Error::VendorConsentCreateError, "consentRecordCreated must be set", caller
|
144
|
+
end
|
145
|
+
if @consentRecordLastUpdated.nil?
|
146
|
+
raise IABConsentString::Error::VendorConsentCreateError, "consentRecordLastUpdated must be set", caller
|
147
|
+
end
|
148
|
+
if @consentLanguage.nil?
|
149
|
+
raise IABConsentString::Error::VendorConsentCreateError, "consentLanguage must be set", caller
|
150
|
+
end
|
151
|
+
|
152
|
+
if @vendorListVersion.nil? || @vendorListVersion <=0
|
153
|
+
raise IABConsentString::Error::VendorConsentCreateError, "Invalid value for vendorListVersion:" + @vendorListVersion.to_s, caller
|
154
|
+
end
|
155
|
+
|
156
|
+
if @maxVendorId.nil? || @maxVendorId<=0
|
157
|
+
raise IABConsentString::Error::VendorConsentCreateError, "Invalid value for maxVendorId:" + @maxVendorId.to_s, caller
|
158
|
+
end
|
159
|
+
|
160
|
+
# For range encoding, check if each range entry is valid
|
161
|
+
if @vendorEncodingType == IABConsentString::GDPRConstants::VENDOR_ENCODING_RANGE
|
162
|
+
if @rangeEntries.nil?
|
163
|
+
raise IABConsentString::Error::VendorConsentCreateError, "Range entries must be set", caller
|
164
|
+
end
|
165
|
+
@rangeEntries.each do |rangeEntry|
|
166
|
+
if !rangeEntry.valid(@maxVendorId)
|
167
|
+
raise IABConsentString::Error::VendorConsentCreateError, "Invalid range entries found", caller
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Calculate size of bit buffer in bits
|
173
|
+
bitBufferSizeInBits = 0
|
174
|
+
if (@vendorEncodingType == IABConsentString::GDPRConstants::VENDOR_ENCODING_RANGE)
|
175
|
+
rangeEntrySectionSize = 0
|
176
|
+
@rangeEntries.each do |rangeEntry|
|
177
|
+
rangeEntrySectionSize += rangeEntry.size
|
178
|
+
end
|
179
|
+
bitBufferSizeInBits = IABConsentString::GDPRConstants::RANGE_ENTRY_OFFSET + rangeEntrySectionSize
|
180
|
+
else
|
181
|
+
bitBufferSizeInBits = IABConsentString::GDPRConstants::VENDOR_BITFIELD_OFFSET + @maxVendorId
|
182
|
+
end
|
183
|
+
|
184
|
+
# Create new bit buffer
|
185
|
+
bitsFit = (bitBufferSizeInBits % 8) == 0
|
186
|
+
str = ""
|
187
|
+
for i in (0...(bitBufferSizeInBits / 8 + (bitsFit ? 0 : 1))) do
|
188
|
+
str << 0b00000000
|
189
|
+
end
|
190
|
+
bits = IABConsentString::Bits.new(str.bytes.to_a)
|
191
|
+
|
192
|
+
# Set fields in bit buffer
|
193
|
+
bits.setInt(IABConsentString::GDPRConstants::VERSION_BIT_OFFSET, IABConsentString::GDPRConstants::VERSION_BIT_SIZE, VERSION)
|
194
|
+
bits.setDateTimeToEpochDeciseconds(IABConsentString::GDPRConstants::CREATED_BIT_OFFSET, IABConsentString::GDPRConstants::CREATED_BIT_SIZE, @consentRecordCreated)
|
195
|
+
bits.setDateTimeToEpochDeciseconds(IABConsentString::GDPRConstants::UPDATED_BIT_OFFSET, IABConsentString::GDPRConstants::UPDATED_BIT_SIZE, @consentRecordLastUpdated)
|
196
|
+
bits.setInt(IABConsentString::GDPRConstants::CMP_ID_OFFSET, IABConsentString::GDPRConstants::CMP_ID_SIZE, @cmpId)
|
197
|
+
bits.setInt(IABConsentString::GDPRConstants::CMP_VERSION_OFFSET, IABConsentString::GDPRConstants::CMP_VERSION_SIZE, @cmpVersion)
|
198
|
+
bits.setInt(IABConsentString::GDPRConstants::CONSENT_SCREEN_SIZE_OFFSET, IABConsentString::GDPRConstants::CONSENT_SCREEN_SIZE, @consentScreenId)
|
199
|
+
bits.setSixBitString(IABConsentString::GDPRConstants::CONSENT_LANGUAGE_OFFSET, IABConsentString::GDPRConstants::CONSENT_LANGUAGE_SIZE, @consentLanguage)
|
200
|
+
bits.setInt(IABConsentString::GDPRConstants::VENDOR_LIST_VERSION_OFFSET, IABConsentString::GDPRConstants::VENDOR_LIST_VERSION_SIZE, @vendorListVersion)
|
201
|
+
|
202
|
+
# Set purposes bits
|
203
|
+
for i in (0...IABConsentString::GDPRConstants::PURPOSES_SIZE) do
|
204
|
+
if (@allowedPurposes.include?(i+1))
|
205
|
+
bits.setBit(IABConsentString::GDPRConstants::PURPOSES_OFFSET + i)
|
206
|
+
else
|
207
|
+
bits.unsetBit(IABConsentString::GDPRConstants::PURPOSES_OFFSET + i)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
bits.setInt(IABConsentString::GDPRConstants::MAX_VENDOR_ID_OFFSET, IABConsentString::GDPRConstants::MAX_VENDOR_ID_SIZE, @maxVendorId)
|
212
|
+
bits.setInt(IABConsentString::GDPRConstants::ENCODING_TYPE_OFFSET, IABConsentString::GDPRConstants::ENCODING_TYPE_SIZE, @vendorEncodingType)
|
213
|
+
|
214
|
+
# Set the bit field or range sections
|
215
|
+
if (@vendorEncodingType == IABConsentString::GDPRConstants::VENDOR_ENCODING_RANGE)
|
216
|
+
# Range encoding
|
217
|
+
if (@defaultConsent)
|
218
|
+
bits.setBit(IABConsentString::GDPRConstants::DEFAULT_CONSENT_OFFSET)
|
219
|
+
else
|
220
|
+
bits.unsetBit(IABConsentString::GDPRConstants::DEFAULT_CONSENT_OFFSET)
|
221
|
+
end
|
222
|
+
bits.setInt(IABConsentString::GDPRConstants::NUM_ENTRIES_OFFSET, IABConsentString::GDPRConstants::NUM_ENTRIES_SIZE, @rangeEntries.size)
|
223
|
+
|
224
|
+
currentOffset = IABConsentString::GDPRConstants::RANGE_ENTRY_OFFSET
|
225
|
+
|
226
|
+
@rangeEntries.each do |rangeEntry|
|
227
|
+
currentOffset = rangeEntry.appendTo(bits, currentOffset)
|
228
|
+
end
|
229
|
+
else
|
230
|
+
# Bit field encoding
|
231
|
+
for i in (0...@maxVendorId) do
|
232
|
+
if @vendorsBitField.include?(i+1)
|
233
|
+
bits.setBit(IABConsentString::GDPRConstants::VENDOR_BITFIELD_OFFSET+i)
|
234
|
+
else
|
235
|
+
bits.unsetBit(IABConsentString::GDPRConstants::VENDOR_BITFIELD_OFFSET+i)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
IABConsentString::Consent::Implementation::V1::ByteBufferBackedVendorConsent.new(bits)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module IABConsentString
|
2
|
+
module Consent
|
3
|
+
module Range
|
4
|
+
class RangeEntry
|
5
|
+
# Append this range entry to the bit buffer
|
6
|
+
# @param buffer [Bits] bit buffer
|
7
|
+
# @param currentOffset [Integer] current offset in the buffer
|
8
|
+
# @return [Integer] new offset
|
9
|
+
def appendTo(buffer, currentOffset)
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
# Check if range entry is valid for the specified max vendor id
|
14
|
+
# @param maxVendorId [Integer] max vendor id
|
15
|
+
# @return [Boolean] true if range entry is valid, false otherwise
|
16
|
+
def valid(maxVendorId)
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'iab_consent_string/consent/range/range_entry'
|
2
|
+
require 'iab_consent_string/gdpr_constants'
|
3
|
+
|
4
|
+
module IABConsentString
|
5
|
+
module Consent
|
6
|
+
module Range
|
7
|
+
class SingleRangeEntry < RangeEntry
|
8
|
+
|
9
|
+
def initialize(singleVendorId)
|
10
|
+
@singleVendorId = singleVendorId
|
11
|
+
end
|
12
|
+
|
13
|
+
def size()
|
14
|
+
# One bit for SingleOrRange flag, VENDOR_ID_SIZE for single vendor ID
|
15
|
+
1 + IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
16
|
+
end
|
17
|
+
|
18
|
+
def appendTo(buffer, currentOffset)
|
19
|
+
newOffset = currentOffset
|
20
|
+
buffer.unsetBit(newOffset)
|
21
|
+
newOffset += 1
|
22
|
+
buffer.setInt(newOffset, IABConsentString::GDPRConstants::VENDOR_ID_SIZE, @singleVendorId)
|
23
|
+
newOffset += IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
24
|
+
newOffset
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid(maxVendorId)
|
28
|
+
(@singleVendorId > 0) && (@singleVendorId <= maxVendorId)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'iab_consent_string/consent/range/range_entry'
|
2
|
+
require 'iab_consent_string/gdpr_constants'
|
3
|
+
|
4
|
+
module IABConsentString
|
5
|
+
module Consent
|
6
|
+
module Range
|
7
|
+
class StartEndRangeEntry < RangeEntry
|
8
|
+
|
9
|
+
def initialize(startVendorId,endVendorId)
|
10
|
+
@startVendorId = startVendorId
|
11
|
+
@endVendorId = endVendorId
|
12
|
+
end
|
13
|
+
|
14
|
+
def size()
|
15
|
+
# One bit for SingleOrRange flag, 2 * VENDOR_ID_SIZE for 2 vendor IDs
|
16
|
+
1 + ( IABConsentString::GDPRConstants::VENDOR_ID_SIZE * 2 )
|
17
|
+
end
|
18
|
+
|
19
|
+
def appendTo(buffer, currentOffset)
|
20
|
+
newOffset = currentOffset
|
21
|
+
buffer.setBit(newOffset)
|
22
|
+
newOffset += 1
|
23
|
+
buffer.setInt(newOffset, IABConsentString::GDPRConstants::VENDOR_ID_SIZE, @startVendorId)
|
24
|
+
newOffset += IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
25
|
+
buffer.setInt(newOffset, IABConsentString::GDPRConstants::VENDOR_ID_SIZE, @endVendorId)
|
26
|
+
newOffset += IABConsentString::GDPRConstants::VENDOR_ID_SIZE
|
27
|
+
newOffset
|
28
|
+
end
|
29
|
+
|
30
|
+
def valid(maxVendorId)
|
31
|
+
(@startVendorId > 0) && (@endVendorId > 0) && (@startVendorId < @endVendorId) && (@endVendorId <= maxVendorId)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module IABConsentString
|
2
|
+
module Consent
|
3
|
+
class VendorConsent
|
4
|
+
# @return [Integer] the version of consent string format
|
5
|
+
def getVersion
|
6
|
+
raise NotImplementedError
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [Timestamp] the time (milli since epoch) at which the consent string was created
|
10
|
+
def getConsentRecordCreated
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Timestamp] the time (milli since epoch) at which the consent string was last updated
|
15
|
+
def getConsentRecordLastUpdated
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Integer] the Consent Manager Provider ID that last updated the consent string
|
20
|
+
def getCmpId
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Integer] the Consent Manager Provider version
|
25
|
+
def getCmpVersion
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Integer] the screen number in the CMP where consent was given
|
30
|
+
def getConsentScreen
|
31
|
+
raise NotImplementedError
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Char(2)] the two-letter ISO639-1 language code that CMP asked for consent in
|
35
|
+
def getConsentLanguage
|
36
|
+
raise NotImplementedError
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Integer] version of vendor list used in most recent consent string update.
|
40
|
+
def getVendorListVersion
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Set<Integer>] the set of purpose id's which are permitted according to this consent string
|
45
|
+
def getAllowedPurposesIds
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Set<Purpose>] the set of allowed purposes which are permitted according to this consent string
|
50
|
+
def getAllowedPurposes
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Integer] an integer equivalent of allowed purpose id bits according to this consent string
|
55
|
+
def getAllowedPurposesBits
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Integer] the maximum VendorId for which consent values are given.
|
60
|
+
def getMaxVendorId
|
61
|
+
raise NotImplementedError
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check wether purpose with specified ID is allowed
|
65
|
+
# @param purposeId [Integer] purpose ID
|
66
|
+
# @return [Boolean] true if purpose is allowed in this consent, false otherwise
|
67
|
+
def isPurposeIdAllowed(purposeId)
|
68
|
+
raise NotImplementedError
|
69
|
+
end
|
70
|
+
|
71
|
+
# Check wether specified purpose is allowed
|
72
|
+
# @param purpose [Purpose] purpose to check
|
73
|
+
# @return [Boolean] true if purpose is allowed in this consent, false otherwise
|
74
|
+
def isPurposeAllowed(purpose)
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check wether vendor with specified ID is allowed
|
79
|
+
# @param vendorId [Integer] vendor ID
|
80
|
+
# @return [Boolean] true if vendor is allowed in this consent, false otherwise
|
81
|
+
def isVendorAllowed(vendorId)
|
82
|
+
raise NotImplementedError
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Array<Byte>] the value of this consent as byte array
|
86
|
+
def toByteArray
|
87
|
+
raise NotImplementedError
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'iab_consent_string/bits'
|
3
|
+
require 'iab_consent_string/gdpr_constants'
|
4
|
+
require 'iab_consent_string/consent/implementation/v1/byte_buffer_backed_vendor_consent'
|
5
|
+
|
6
|
+
module IABConsentString
|
7
|
+
module Consent
|
8
|
+
# IABConsentString::Consent::VendorConsent decoder from Base64 string. Right now only version 1 is know, but eventually
|
9
|
+
# this can be extended to support new versions
|
10
|
+
class VendorConsentDecoder
|
11
|
+
# Build a IABConsentString::Consent::VendorConsent object from a base64 string
|
12
|
+
# @params consentString [String] a url safe base64 encoded consent string
|
13
|
+
# @return [IABConsentString::Consent::VendorConsent] a VendorConsent object
|
14
|
+
# @raise an error when there's a problem with the consentString passed
|
15
|
+
def self.fromBase64String(consentString)
|
16
|
+
if consentString.nil?
|
17
|
+
raise "Null or empty consent string passed as an argument"
|
18
|
+
end
|
19
|
+
fromByteArray(Base64.urlsafe_decode64(consentString).bytes.to_a)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.fromByteArray(bytes)
|
23
|
+
if ( bytes.nil? || bytes.length == 0)
|
24
|
+
raise "Null or empty consent string passed as an argument"
|
25
|
+
end
|
26
|
+
bits = Bits.new(bytes)
|
27
|
+
version = getVersion(bits)
|
28
|
+
case version
|
29
|
+
when 1
|
30
|
+
IABConsentString::Consent::Implementation::V1::ByteBufferBackedVendorConsent.new(bits)
|
31
|
+
else
|
32
|
+
raise "Unsupported version: " + version.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.getVersion(bits)
|
37
|
+
bits.getInt(IABConsentString::GDPRConstants::VERSION_BIT_OFFSET, IABConsentString::GDPRConstants::VERSION_BIT_SIZE)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module IABConsentString
|
4
|
+
module Consent
|
5
|
+
class VendorConsentEncoder
|
6
|
+
# Encode vendor consent to Base64 string
|
7
|
+
# @param vendorConsent [VendorConsent] vendor consent
|
8
|
+
# @return [String] Base64 encoded string
|
9
|
+
def self.toBase64String(vendorConsent)
|
10
|
+
# Encode Without Padding to respect IAB Consent String Spec
|
11
|
+
Base64.urlsafe_encode64(vendorConsent.toByteArray().pack("C*") , padding: false)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module IABConsentString
|
2
|
+
class GDPRConstants
|
3
|
+
VENDOR_ENCODING_RANGE = 1
|
4
|
+
VERSION_BIT_OFFSET = 0
|
5
|
+
VERSION_BIT_SIZE = 6
|
6
|
+
CREATED_BIT_OFFSET = 6
|
7
|
+
CREATED_BIT_SIZE = 36
|
8
|
+
UPDATED_BIT_OFFSET = 42
|
9
|
+
UPDATED_BIT_SIZE = 36
|
10
|
+
CMP_ID_OFFSET = 78
|
11
|
+
CMP_ID_SIZE = 12
|
12
|
+
CMP_VERSION_OFFSET = 90
|
13
|
+
CMP_VERSION_SIZE = 12
|
14
|
+
CONSENT_SCREEN_SIZE_OFFSET = 102
|
15
|
+
CONSENT_SCREEN_SIZE = 6
|
16
|
+
CONSENT_LANGUAGE_OFFSET = 108
|
17
|
+
CONSENT_LANGUAGE_SIZE = 12
|
18
|
+
VENDOR_LIST_VERSION_OFFSET = 120
|
19
|
+
VENDOR_LIST_VERSION_SIZE = 12
|
20
|
+
PURPOSES_OFFSET = 132
|
21
|
+
PURPOSES_SIZE = 24
|
22
|
+
MAX_VENDOR_ID_OFFSET = 156
|
23
|
+
MAX_VENDOR_ID_SIZE = 16
|
24
|
+
ENCODING_TYPE_OFFSET = 172
|
25
|
+
ENCODING_TYPE_SIZE = 1
|
26
|
+
VENDOR_BITFIELD_OFFSET = 173
|
27
|
+
DEFAULT_CONSENT_OFFSET = 173
|
28
|
+
NUM_ENTRIES_OFFSET = 174
|
29
|
+
NUM_ENTRIES_SIZE = 12
|
30
|
+
RANGE_ENTRY_OFFSET = 186
|
31
|
+
VENDOR_ID_SIZE = 16
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Enumeration of currently defined purposes by IAB
|
2
|
+
# @see <a href="https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework">https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework</a>
|
3
|
+
module IABConsentString
|
4
|
+
class Purpose
|
5
|
+
# The storage of information, or access to information that is already stored, on user device such as accessing advertising identifiers
|
6
|
+
# and/or other device identifiers, and/or using cookies or similar technologies.
|
7
|
+
STORAGE_AND_ACCESS = 1
|
8
|
+
# The collection and processing of information about user of a site to subsequently personalize advertising for them in other contexts,
|
9
|
+
# i.e. on other sites or apps, over time. Typically, the content of the site or app is used to make inferences about user interests, which inform future selections.
|
10
|
+
PERSONALIZATION = 2
|
11
|
+
# The collection of information and combination with previously collected information, to select and deliver advertisements and to measure the delivery
|
12
|
+
# and effectiveness of such advertisements. This includes using previously collected information about user interests to select ads, processing data about
|
13
|
+
# what advertisements were shown, how often they were shown, when and where they were shown, and whether they took any action related to the advertisement,
|
14
|
+
# including for example clicking an ad or making a purchase.
|
15
|
+
AD_SELECTION = 3
|
16
|
+
# The collection of information, and combination with previously collected information, to select and deliver content and to measure the delivery and
|
17
|
+
# effectiveness of such content. This includes using previously collected information about user interests to select content, processing data about
|
18
|
+
# what content was shown, how often or how long it was shown, when and where it was shown, and whether they took any action related to the content,
|
19
|
+
# including for example clicking on content.
|
20
|
+
CONTENT_DELIVERY = 4
|
21
|
+
# The collection of information about user use of content, and combination with previously collected information, used to measure, understand,
|
22
|
+
# and report on user usage of content.
|
23
|
+
MEASUREMENT = 5
|
24
|
+
# Ads targeted on geolocalization
|
25
|
+
GEOLOCALIZED_ADS = 6
|
26
|
+
# Purpose ID that is currently not defined
|
27
|
+
UNDEFINED = -1
|
28
|
+
|
29
|
+
def initialize(id)
|
30
|
+
case id
|
31
|
+
when STORAGE_AND_ACCESS, PERSONALIZATION, AD_SELECTION, CONTENT_DELIVERY, MEASUREMENT, GEOLOCALIZED_ADS
|
32
|
+
@id = id
|
33
|
+
else
|
34
|
+
@id = -1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def getId
|
39
|
+
@id
|
40
|
+
end
|
41
|
+
|
42
|
+
def eql?(other)
|
43
|
+
@id == other.getId
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(other)
|
47
|
+
@id == other.getId
|
48
|
+
end
|
49
|
+
|
50
|
+
def valueOf()
|
51
|
+
case @id
|
52
|
+
when STORAGE_AND_ACCESS
|
53
|
+
return "STORAGE_AND_ACCESS"
|
54
|
+
when PERSONALIZATION
|
55
|
+
return "PERSONALIZATION"
|
56
|
+
when AD_SELECTION
|
57
|
+
return "AD_SELECTION"
|
58
|
+
when CONTENT_DELIVERY
|
59
|
+
return "CONTENT_DELIVERY"
|
60
|
+
when MEASUREMENT
|
61
|
+
return "MEASUREMENT"
|
62
|
+
when GEOLOCALIZED_ADS
|
63
|
+
return "GEOLOCALIZED_ADS"
|
64
|
+
else
|
65
|
+
return "UNDEFINED"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'iab_consent_string/bits'
|
2
|
+
|
3
|
+
module IABConsentString
|
4
|
+
module Util
|
5
|
+
class Utils
|
6
|
+
# Create bit buffer from string representation
|
7
|
+
# @param binaryString [String] binary string
|
8
|
+
# @return [Bits] bit buffer
|
9
|
+
def self.fromBinaryString(binaryString)
|
10
|
+
length = binaryString.length
|
11
|
+
bitsFit = (length % 8) == 0
|
12
|
+
str = ""
|
13
|
+
for i in (0...length / 8 + (bitsFit ? 0 : 1)) do
|
14
|
+
str << 0b00000000
|
15
|
+
end
|
16
|
+
bits = IABConsentString::Bits.new(str.bytes.to_a)
|
17
|
+
for i in (0...length) do
|
18
|
+
if binaryString[i] == '1'
|
19
|
+
bits.setBit(i)
|
20
|
+
else
|
21
|
+
bits.unsetBit(i)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
bits
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iab_consent_string
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fidzup Coding Star Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-23 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: |-
|
14
|
+
This library is a Ruby reference implementation for dealing with consent strings in the IAB EU's GDPR Transparency and Consent Framework.
|
15
|
+
It should be used by anyone who receives or sends consent information like vendors that receive consent data from a partner, or consent management platforms that need to encode/decode the global cookie.
|
16
|
+
|
17
|
+
The IAB specification for the consent string format is available on the IAB Github (section 'Vendor Consent Cookie Format').
|
18
|
+
|
19
|
+
This library supports the version v1.1 of the specification. It can encode and decode consent strings with version bit 1.
|
20
|
+
email: coding.stars@fidzup.com
|
21
|
+
executables: []
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- lib/iab_consent_string.rb
|
26
|
+
- lib/iab_consent_string/bits.rb
|
27
|
+
- lib/iab_consent_string/consent/implementation/v1/byte_buffer_backed_vendor_consent.rb
|
28
|
+
- lib/iab_consent_string/consent/implementation/v1/vendor_consent_builder.rb
|
29
|
+
- lib/iab_consent_string/consent/range/range_entry.rb
|
30
|
+
- lib/iab_consent_string/consent/range/single_range_entry.rb
|
31
|
+
- lib/iab_consent_string/consent/range/start_end_range_entry.rb
|
32
|
+
- lib/iab_consent_string/consent/vendor_consent.rb
|
33
|
+
- lib/iab_consent_string/consent/vendor_consent_decoder.rb
|
34
|
+
- lib/iab_consent_string/consent/vendor_consent_encoder.rb
|
35
|
+
- lib/iab_consent_string/error/vendor_consent_create_error.rb
|
36
|
+
- lib/iab_consent_string/error/vendor_consent_error.rb
|
37
|
+
- lib/iab_consent_string/error/vendor_consent_parse_error.rb
|
38
|
+
- lib/iab_consent_string/gdpr_constants.rb
|
39
|
+
- lib/iab_consent_string/purpose.rb
|
40
|
+
- lib/iab_consent_string/util/utils.rb
|
41
|
+
homepage: https://rubygems.org/gems/iab_consent_string
|
42
|
+
licenses:
|
43
|
+
- MIT
|
44
|
+
metadata:
|
45
|
+
source_code_uri: https://github.com/Fidzup/Consent-String-SDK-Ruby
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.5.2.3
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: Encode and decode web-safe base64 consent information with the IAB EU's GDPR
|
66
|
+
Transparency and Consent Framework.
|
67
|
+
test_files: []
|