Skip to content

Commit f43b546

Browse files
authored
Merge pull request #54 from spotify/20200131-expose-lexer
Expose redactor
2 parents 1efa7b1 + b23dbdc commit f43b546

File tree

4 files changed

+151
-28
lines changed

4 files changed

+151
-28
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2020 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
import Foundation
21+
22+
public class LexRedactor: LogRedactor {
23+
private static let redactedTemplate = "/Users/<redacted>/"
24+
private lazy var userDirRegex: NSRegularExpression? = {
25+
do {
26+
return try NSRegularExpression(pattern: "\\/Users\\/(\\w*)\\/")
27+
} catch {
28+
return nil
29+
}
30+
}()
31+
public var userDirToRedact: String?
32+
33+
public func redactUserDir(string: String) -> String {
34+
guard let regex = userDirRegex else {
35+
return string
36+
}
37+
if let userDirToRedact = userDirToRedact {
38+
return string.replacingOccurrences(of: userDirToRedact, with: Self.redactedTemplate)
39+
} else {
40+
guard let firstMatch = regex.firstMatch(in: string,
41+
options: [],
42+
range: NSRange(location: 0, length: string.count)) else {
43+
return string
44+
}
45+
let userDir = string.substring(firstMatch.range)
46+
userDirToRedact = userDir
47+
return string.replacingOccurrences(of: userDir, with: Self.redactedTemplate)
48+
}
49+
}
50+
}

Sources/XCLogParser/lexer/Lexer.swift

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,24 @@ import Foundation
2222
public final class Lexer {
2323

2424
static let SLFHeader = "SLF"
25-
static let redactedTemplate = "/Users/<redacted>/"
2625

2726
let typeDelimiters: CharacterSet
2827
let filePath: String
2928
var classNames = [String]()
30-
var userDirToRedact: String?
31-
32-
lazy var userDirRegex: NSRegularExpression? = {
33-
do {
34-
return try NSRegularExpression(pattern: "\\/Users\\/(\\w*)\\/")
35-
} catch {
36-
return nil
29+
var userDirToRedact: String? {
30+
set {
31+
redactor.userDirToRedact = newValue
32+
}
33+
get {
34+
redactor.userDirToRedact
3735
}
38-
}()
36+
}
37+
private var redactor: LogRedactor
3938

4039
public init(filePath: String) {
4140
self.filePath = filePath
4241
self.typeDelimiters = CharacterSet(charactersIn: TokenType.all())
42+
self.redactor = LexRedactor()
4343
}
4444

4545
/// Tokenizes an xcactivitylog serialized in the `SLF` format
@@ -188,7 +188,7 @@ public final class Lexer {
188188
#endif
189189
scanner.scanLocation += value
190190
if redacted {
191-
return redactUserDir(string: String(scanner.string[start..<end]))
191+
return redactor.redactUserDir(string: String(scanner.string[start..<end]))
192192
}
193193
return String(scanner.string[start..<end])
194194
}
@@ -200,24 +200,6 @@ public final class Lexer {
200200
let result = Double(bitPattern: beValue.byteSwapped)
201201
return result
202202
}
203-
204-
private func redactUserDir(string: String) -> String {
205-
guard let regex = userDirRegex else {
206-
return string
207-
}
208-
if let userDirToRedact = userDirToRedact {
209-
return string.replacingOccurrences(of: userDirToRedact, with: Self.redactedTemplate)
210-
} else {
211-
guard let firstMatch = regex.firstMatch(in: string,
212-
options: [],
213-
range: NSRange(location: 0, length: string.count)) else {
214-
return string
215-
}
216-
let userDir = string.substring(firstMatch.range)
217-
userDirToRedact = userDir
218-
return string.replacingOccurrences(of: userDir, with: Self.redactedTemplate)
219-
}
220-
}
221203
}
222204

223205
extension Scanner {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2020 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
public protocol LogRedactor {
21+
/// Predefined (or inferrred during redation process) user home path.
22+
/// Introduced for better performance.
23+
var userDirToRedact: String? {get set}
24+
25+
/// Redacts a string by replacing sensitive username path with a template
26+
/// - parameter string: The string to redact
27+
/// - returns: Redacted text with
28+
func redactUserDir(string: String) -> String
29+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) 2020 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
import Foundation
21+
import XCTest
22+
@testable import XCLogParser
23+
24+
class LexRedactorTests: XCTestCase {
25+
let redactor = LexRedactor()
26+
27+
func testRedacting() {
28+
29+
let redactedText = redactor.redactUserDir(string: "Some /Users/private/path")
30+
31+
XCTAssertEqual(redactedText, "Some /Users/<redacted>/path")
32+
}
33+
34+
func testMultiplePathsRedacting() {
35+
36+
let redactedText = redactor.redactUserDir(string: "Some /Users/private/path and other /Users/private/path2")
37+
38+
XCTAssertEqual(redactedText, "Some /Users/<redacted>/path and other /Users/<redacted>/path2")
39+
}
40+
41+
func testRedactingFillsUserDir() {
42+
_ = redactor.redactUserDir(string: "Some /Users/private/path")
43+
44+
XCTAssertEqual(redactor.userDirToRedact, "/Users/private/")
45+
}
46+
47+
func testPredefinedUserDirIsRedacted() {
48+
redactor.userDirToRedact = "/Users/private/"
49+
50+
let redactedText = redactor.redactUserDir(string: "Some /Users/private/path")
51+
52+
XCTAssertEqual(redactedText, "Some /Users/<redacted>/path")
53+
}
54+
55+
func testNotInPredefinedUserDirIsNotRedacted() {
56+
redactor.userDirToRedact = "/Users/priv/"
57+
58+
let redactedText = redactor.redactUserDir(string: "Some /Users/private/path")
59+
60+
XCTAssertEqual(redactedText, "Some /Users/private/path")
61+
}
62+
}

0 commit comments

Comments
 (0)