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.
@@ -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,8 @@
1
+ require 'iab_consent_string/error/vendor_consent_error'
2
+
3
+ module IABConsentString
4
+ module Error
5
+ class VendorConsentCreateError < IABConsentString::Error::VendorConsentError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module IABConsentString
2
+ module Error
3
+ class VendorConsentError < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require 'iab_consent_string/error/vendor_consent_error'
2
+
3
+ module IABConsentString
4
+ module Error
5
+ class VendorConsentParseError < IABConsentString::Error::VendorConsentError
6
+ end
7
+ end
8
+ 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: []