iab_consent_string 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|