forked from github/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTelemetryCleaner.swift
More file actions
86 lines (74 loc) · 3.29 KB
/
TelemetryCleaner.swift
File metadata and controls
86 lines (74 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import Foundation
// reference the redact algorithm from https://github.com/microsoft/vscode/blame/main/src/vs/platform/telemetry/common/telemetryUtils.ts
public struct TelemetryCleaner {
private let cleanupPatterns: [NSRegularExpression]
public init(cleanupPatterns: [NSRegularExpression]) {
self.cleanupPatterns = cleanupPatterns
}
public func redactMap(_ data: [String: Any]?) -> [String: Any]? {
guard let data = data else {
return nil
}
return data.mapValues { value in
if let stringValue = value as? String {
return redact(stringValue) ?? ""
}
return value
}
}
public func redact(_ value: String?) -> String? {
guard let value = value else {
return nil
}
var cleanedValue = value.replacingOccurrences(of: "%20", with: " ")
cleanedValue = anonymizeFilePaths(cleanedValue)
cleanedValue = removeUserInfo(cleanedValue)
return cleanedValue
}
private func anonymizeFilePaths(_ stack: String) -> String {
guard stack.contains("/") || stack.contains("\\") else {
return stack
}
var updatedStack = stack
for pattern in cleanupPatterns {
updatedStack = pattern.stringByReplacingMatches(
in: updatedStack,
range: NSRange(updatedStack.startIndex..., in: updatedStack),
withTemplate: ""
)
}
// Replace file paths with redacted marker
let filePattern = try! NSRegularExpression(
pattern: "(file:\\/\\/)?([a-zA-Z]:(\\\\|\\/)|(\\\\\\\\/|\\\\|\\/))?([\\w-\\._]+(\\\\|\\/))+"
)
updatedStack = filePattern.stringByReplacingMatches(
in: updatedStack,
range: NSRange(updatedStack.startIndex..., in: updatedStack),
withTemplate: "<REDACTED: user-file-path>"
)
return updatedStack
}
private func removeUserInfo(_ value: String) -> String {
let patterns: [(label: String, pattern: String)] = [
("Google API Key", "AIza[A-Za-z0-9_\\\\\\-]{35}"),
("Slack Token", "xox[pbar]\\-[A-Za-z0-9]"),
("GitHub Token", "(gh[psuro]_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59})"),
("Generic Secret", "(key|token|sig|secret|signature|password|passwd|pwd|android:value)[^a-zA-Z0-9]"),
("CLI Credentials", "((login|psexec|(certutil|psexec)\\.exe).{1,50}(\\s-u(ser(name)?)?\\s+.{3,100})?\\s-(admin|user|vm|root)?p(ass(word)?)?\\s+[\"']?[^$\\-\\/\\s]|(^|[\\s\\r\\n\\])net(\\.exe)?.{1,5}(user\\s+|share\\s+\\/user:| user -? secrets ? set) \\s + [^ $\\s \\/])"),
("Microsoft Entra ID", "eyJ(?:0eXAiOiJKV1Qi|hbGci|[a-zA-Z0-9\\-_]+\\.[a-zA-Z0-9\\-_]+\\.)"),
("Email", "@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-]+")
]
var cleanedValue = value
for (label, pattern) in patterns {
if let regex = try? NSRegularExpression(pattern: pattern) {
if regex.firstMatch(
in: cleanedValue,
range: NSRange(cleanedValue.startIndex..., in: cleanedValue)
) != nil {
return "<REDACTED: \(label)>"
}
}
}
return cleanedValue
}
}