@@ -13,6 +13,7 @@ import (
13
13
"context"
14
14
"crypto/sha256"
15
15
"encoding/base64"
16
+ "encoding/json"
16
17
"errors"
17
18
"fmt"
18
19
"math"
@@ -131,71 +132,105 @@ func (sd *SyncData) getCurrentChannels() base.Set {
131
132
return ch
132
133
}
133
134
134
- func (sd * SyncData ) HashRedact (salt string ) SyncData {
135
-
136
- // Creating a new SyncData with the redacted info. We copy all the information which stays the same and create new
137
- // items for the redacted data. The data to be redacted is populated below.
138
- redactedSyncData := SyncData {
139
- CurrentRev : sd .CurrentRev ,
140
- NewestRev : sd .NewestRev ,
141
- Flags : sd .Flags ,
142
- Sequence : sd .Sequence ,
143
- UnusedSequences : sd .UnusedSequences ,
144
- RecentSequences : sd .RecentSequences ,
145
- History : RevTree {},
146
- Channels : channels.ChannelMap {},
147
- Access : UserAccessMap {},
148
- RoleAccess : UserAccessMap {},
149
- Expiry : sd .Expiry ,
150
- Cas : sd .Cas ,
151
- Crc32c : sd .Crc32c ,
152
- TombstonedAt : sd .TombstonedAt ,
153
- Attachments : AttachmentsMeta {},
154
- }
155
-
156
- // Populate and redact channels
135
+ // RedactRawGlobalSyncData runs HashRedact on the given global sync data.
136
+ func RedactRawGlobalSyncData (syncData []byte , redactSalt string ) ([]byte , error ) {
137
+ if redactSalt == "" {
138
+ return nil , fmt .Errorf ("redact salt must be set" )
139
+ }
140
+
141
+ var gsd GlobalSyncData
142
+ if err := json .Unmarshal (syncData , & gsd ); err != nil {
143
+ return nil , fmt .Errorf ("couldn't unmarshal sync data: %w" , err )
144
+ }
145
+
146
+ if err := gsd .HashRedact (redactSalt ); err != nil {
147
+ return nil , fmt .Errorf ("couldn't redact global sync data: %w" , err )
148
+ }
149
+
150
+ return json .Marshal (gsd )
151
+ }
152
+
153
+ // HashRedact does in-place redaction of UserData inside GlobalSyncData, by hashing attachment names.
154
+ func (gsd * GlobalSyncData ) HashRedact (salt string ) error {
155
+ for k , v := range gsd .GlobalAttachments {
156
+ gsd .GlobalAttachments [base .Sha1HashString (k , salt )] = v
157
+ delete (gsd .GlobalAttachments , k )
158
+ }
159
+ return nil
160
+ }
161
+
162
+ // RedactRawSyncData runs HashRedact on the given sync data.
163
+ func RedactRawSyncData (syncData []byte , redactSalt string ) ([]byte , error ) {
164
+ if redactSalt == "" {
165
+ return nil , fmt .Errorf ("redact salt must be set" )
166
+ }
167
+
168
+ var sd SyncDataAlias
169
+ if err := json .Unmarshal (syncData , & sd ); err != nil {
170
+ return nil , fmt .Errorf ("couldn't unmarshal sync data: %w" , err )
171
+ }
172
+
173
+ if err := sd .HashRedact (redactSalt ); err != nil {
174
+ return nil , fmt .Errorf ("couldn't redact sync data: %w" , err )
175
+ }
176
+
177
+ return json .Marshal (sd )
178
+ }
179
+
180
+ // HashRedact does in-place redaction of UserData inside SyncData, by hashing channel names, user access, role access, and attachment names.
181
+ func (sd * SyncDataAlias ) HashRedact (salt string ) error {
182
+
183
+ // Redact channel names
157
184
for k , v := range sd .Channels {
158
- redactedSyncData .Channels [base .Sha1HashString (k , salt )] = v
185
+ sd .Channels [base .Sha1HashString (k , salt )] = v
186
+ delete (sd .Channels , k )
187
+ }
188
+ for i , v := range sd .ChannelSet {
189
+ sd .ChannelSet [i ].Name = base .Sha1HashString (v .Name , salt )
190
+ }
191
+ for i , v := range sd .ChannelSetHistory {
192
+ sd .ChannelSetHistory [i ].Name = base .Sha1HashString (v .Name , salt )
159
193
}
160
194
161
- // Populate and redact history. This is done as it also includes channel names
195
+ // Redact history. This is done as it also includes channel names
162
196
for k , revInfo := range sd .History {
163
-
164
197
if revInfo .Channels != nil {
165
- redactedChannels := base.Set {}
198
+ redactedChannels := make ( base.Set , len ( revInfo . Channels ))
166
199
for existingChanKey := range revInfo .Channels {
167
200
redactedChannels .Add (base .Sha1HashString (existingChanKey , salt ))
168
201
}
169
202
revInfo .Channels = redactedChannels
170
203
}
171
-
172
- redactedSyncData .History [k ] = revInfo
204
+ sd .History [k ] = revInfo
173
205
}
174
206
175
- // Populate and redact user access
207
+ // Redact user access
176
208
for k , v := range sd .Access {
177
209
accessTimerSet := map [string ]channels.VbSequence {}
178
210
for channelName , vbStats := range v {
179
211
accessTimerSet [base .Sha1HashString (channelName , salt )] = vbStats
180
212
}
181
- redactedSyncData .Access [base .Sha1HashString (k , salt )] = accessTimerSet
213
+ sd .Access [base .Sha1HashString (k , salt )] = accessTimerSet
214
+ delete (sd .Access , k )
182
215
}
183
216
184
- // Populate and redact user role access
217
+ // Redact user role access
185
218
for k , v := range sd .RoleAccess {
186
219
accessTimerSet := map [string ]channels.VbSequence {}
187
220
for channelName , vbStats := range v {
188
221
accessTimerSet [base .Sha1HashString (channelName , salt )] = vbStats
189
222
}
190
- redactedSyncData .RoleAccess [base .Sha1HashString (k , salt )] = accessTimerSet
223
+ sd .RoleAccess [base .Sha1HashString (k , salt )] = accessTimerSet
224
+ delete (sd .RoleAccess , k )
191
225
}
192
226
193
- // Populate and redact attachment names
227
+ // Redact attachment names (pre-4.0 attachment location)
194
228
for k , v := range sd .Attachments {
195
- redactedSyncData .Attachments [base .Sha1HashString (k , salt )] = v
229
+ sd .Attachments [base .Sha1HashString (k , salt )] = v
230
+ delete (sd .Attachments , k )
196
231
}
197
232
198
- return redactedSyncData
233
+ return nil
199
234
}
200
235
201
236
// A document as stored in Couchbase. Contains the body of the current revision plus metadata.
0 commit comments