Simplify Secrets module — get rid of protocol. Just reference SecretKey properties as static.
This commit is contained in:
parent
1eacebe546
commit
45cd018020
2
.gitignore
vendored
2
.gitignore
vendored
@ -74,4 +74,6 @@ fastlane/test_output
|
||||
/Frameworks/Secrets/Secrets.swift
|
||||
Secrets/Sources/Secrets/Secrets.swift
|
||||
*.py[cod]
|
||||
/Secrets/Sources/Secrets/SecretKey.swift
|
||||
/Modules/Secrets/Sources/Secrets/SecretKey.swift
|
||||
|
||||
|
@ -15,10 +15,10 @@ extension OAuthAuthorizationClient {
|
||||
/// Models private NetNewsWire client secrets.
|
||||
/// These placeholders are substituted at build time using a Run Script phase with build settings.
|
||||
/// https://developer.feedly.com/v3/auth/#authenticating-a-user-and-obtaining-an-auth-code
|
||||
return OAuthAuthorizationClient(id: SecretsManager.provider.feedlyClientId,
|
||||
return OAuthAuthorizationClient(id: SecretKey.feedlyClientID,
|
||||
redirectUri: "netnewswire://auth/feedly",
|
||||
state: nil,
|
||||
secret: SecretsManager.provider.feedlyClientSecret)
|
||||
secret: SecretKey.feedlyClientSecret)
|
||||
}
|
||||
|
||||
static var feedlySandboxClient: OAuthAuthorizationClient {
|
||||
|
@ -56,7 +56,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
|
||||
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
|
||||
for cookie in cookies where cookie.name == Self.SessionIdCookie {
|
||||
let credentials = Credentials(type: .newsBlurSessionId, username: username, secret: cookie.value)
|
||||
let credentials = Credentials(type: .newsBlurSessionID, username: username, secret: cookie.value)
|
||||
completion(.success(credentials))
|
||||
return
|
||||
}
|
||||
|
@ -609,7 +609,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
|
||||
}
|
||||
|
||||
func accountDidInitialize(_ account: Account) {
|
||||
credentials = try? account.retrieveCredentials(type: .newsBlurSessionId)
|
||||
credentials = try? account.retrieveCredentials(type: .newsBlurSessionID)
|
||||
}
|
||||
|
||||
func accountWillBeDeleted(_ account: Account) {
|
||||
|
@ -693,8 +693,8 @@ private extension ReaderAPICaller {
|
||||
|
||||
func addVariantHeaders(_ request: inout URLRequest) {
|
||||
if variant == .inoreader {
|
||||
request.addValue(SecretsManager.provider.inoreaderAppId, forHTTPHeaderField: "AppId")
|
||||
request.addValue(SecretsManager.provider.inoreaderAppKey, forHTTPHeaderField: "AppKey")
|
||||
request.addValue(SecretKey.inoreaderAppID, forHTTPHeaderField: "AppId")
|
||||
request.addValue(SecretKey.inoreaderAppKey, forHTTPHeaderField: "AppKey")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ public extension URLRequest {
|
||||
URLQueryItem(name: "password", value: credentials.secret),
|
||||
]
|
||||
httpBody = postData.enhancedPercentEncodedQuery?.data(using: .utf8)
|
||||
case .newsBlurSessionId:
|
||||
case .newsBlurSessionID:
|
||||
setValue("\(NewsBlurAPICaller.SessionIdCookie)=\(credentials.secret)", forHTTPHeaderField: "Cookie")
|
||||
httpShouldHandleCookies = true
|
||||
case .readerBasic:
|
||||
|
@ -1,18 +0,0 @@
|
||||
//
|
||||
// FeedlyTestSecrets.swift
|
||||
//
|
||||
//
|
||||
// Created by Maurice Parker on 8/4/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Secrets
|
||||
|
||||
struct FeedlyTestSecrets: SecretsProvider {
|
||||
var mercuryClientId = ""
|
||||
var mercuryClientSecret = ""
|
||||
var feedlyClientId = ""
|
||||
var feedlyClientSecret = ""
|
||||
var inoreaderAppId = ""
|
||||
var inoreaderAppKey = ""
|
||||
}
|
@ -19,10 +19,6 @@ class FeedlyTestSupport {
|
||||
var refreshToken = Credentials(type: .oauthRefreshToken, username: "Test", secret: "t3st-refresh-tok3n")
|
||||
var transport = TestTransport()
|
||||
|
||||
init() {
|
||||
SecretsManager.provider = FeedlyTestSecrets()
|
||||
}
|
||||
|
||||
func makeMockNetworkStack() -> (TestTransport, FeedlyAPICaller) {
|
||||
let caller = FeedlyAPICaller(transport: transport, api: .sandbox)
|
||||
caller.credentials = accessToken
|
||||
|
@ -117,7 +117,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
|
||||
crashReporter.enable()
|
||||
#endif
|
||||
|
||||
SecretsManager.provider = Secrets()
|
||||
AccountManager.shared = AccountManager(accountsFolder: Platform.dataSubfolder(forApplication: nil, folderName: "Accounts")!)
|
||||
ArticleThemesManager.shared = ArticleThemesManager(folderPath: Platform.dataSubfolder(forApplication: nil, folderName: "Themes")!)
|
||||
|
||||
|
@ -97,7 +97,7 @@ class AccountsNewsBlurWindowController: NSWindowController {
|
||||
|
||||
do {
|
||||
try self.account?.removeCredentials(type: .newsBlurBasic)
|
||||
try self.account?.removeCredentials(type: .newsBlurSessionId)
|
||||
try self.account?.removeCredentials(type: .newsBlurSessionID)
|
||||
try self.account?.storeCredentials(credentials)
|
||||
try self.account?.storeCredentials(validatedCredentials)
|
||||
|
||||
|
@ -396,7 +396,6 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Resources/NewsFax.nnwtheme,
|
||||
Secrets.swift.gyb,
|
||||
ShareExtension/SafariExt.js,
|
||||
ShareExtension/ShareDefaultContainer.swift,
|
||||
Widget/WidgetData.swift,
|
||||
@ -413,7 +412,6 @@
|
||||
ExtensionPoints/SendToMarsEditCommand.swift,
|
||||
ExtensionPoints/SendToMicroBlogCommand.swift,
|
||||
"Extensions/NSView-Extensions.swift",
|
||||
Secrets.swift.gyb,
|
||||
ShareExtension/SafariExt.js,
|
||||
ShareExtension/ShareDefaultContainer.swift,
|
||||
SmartFeeds/SmartFeedPasteboardWriter.swift,
|
||||
|
24
Package.swift
Normal file
24
Package.swift
Normal file
@ -0,0 +1,24 @@
|
||||
// swift-tools-version: 5.10
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Secrets",
|
||||
platforms: [.macOS(.v14), .iOS(.v17)],
|
||||
products: [
|
||||
.library(
|
||||
name: "Secrets",
|
||||
targets: ["Secrets"]
|
||||
)
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Secrets",
|
||||
dependencies: [],
|
||||
exclude: ["SecretKey.swift.gyb"],
|
||||
swiftSettings: [
|
||||
.enableExperimentalFeature("StrictConcurrency")
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
// swift-tools-version:5.10
|
||||
// swift-tools-version:6.0
|
||||
|
||||
import PackageDescription
|
||||
|
||||
@ -17,7 +17,7 @@ let package = Package(
|
||||
.target(
|
||||
name: "Secrets",
|
||||
dependencies: [],
|
||||
swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
|
||||
exclude: ["SecretKey.swift.gyb"]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
@ -8,15 +8,15 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum CredentialsError: Error {
|
||||
public enum CredentialsError: Error, Sendable {
|
||||
case incompleteCredentials
|
||||
case unhandledError(status: OSStatus)
|
||||
}
|
||||
|
||||
public enum CredentialsType: String {
|
||||
public enum CredentialsType: String, Sendable {
|
||||
case basic = "password"
|
||||
case newsBlurBasic = "newsBlurBasic"
|
||||
case newsBlurSessionId = "newsBlurSessionId"
|
||||
case newsBlurSessionID = "newsBlurSessionId"
|
||||
case readerBasic = "readerBasic"
|
||||
case readerAPIKey = "readerAPIKey"
|
||||
case oauthAccessToken = "oauthAccessToken"
|
||||
@ -24,7 +24,7 @@ public enum CredentialsType: String {
|
||||
case oauthRefreshToken = "oauthRefreshToken"
|
||||
}
|
||||
|
||||
public struct Credentials: Equatable {
|
||||
public struct Credentials: Equatable, Sendable {
|
||||
public let type: CredentialsType
|
||||
public let username: String
|
||||
public let secret: String
|
||||
|
@ -10,7 +10,7 @@ import Foundation
|
||||
|
||||
public struct CredentialsManager {
|
||||
|
||||
private static var keychainGroup: String? = {
|
||||
private static let keychainGroup: String? = {
|
||||
guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String else {
|
||||
return nil
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Generated by Secrets.swift.gyb
|
||||
// Generated by SecretKey.swift.gyb
|
||||
%{
|
||||
import os
|
||||
|
||||
@ -13,40 +13,37 @@ def encode(string, salt):
|
||||
|
||||
def snake_to_camel(snake_str):
|
||||
components = snake_str.split('_')
|
||||
return components[0].lower() + ''.join(x.title() for x in components[1:])
|
||||
components = [components[0].lower()] + [x.title() if x != 'ID' else x for x in components[1:]]
|
||||
camel_case_str = ''.join(components)
|
||||
return camel_case_str
|
||||
|
||||
salt = [byte for byte in os.urandom(64)]
|
||||
}%
|
||||
import Secrets
|
||||
import Foundation
|
||||
|
||||
public struct Secrets: SecretsProvider {
|
||||
public struct SecretKey {
|
||||
% for secret in secrets:
|
||||
|
||||
public var ${snake_to_camel(secret)}: String {
|
||||
public static let ${snake_to_camel(secret)}: String = {
|
||||
let encoded: [UInt8] = [
|
||||
% for chunk in chunks(encode(os.environ.get(secret) or "", salt), 8):
|
||||
${"".join(["0x%02x, " % byte for byte in chunk])}
|
||||
% end
|
||||
]
|
||||
|
||||
return decode(encoded, salt: salt)
|
||||
}
|
||||
return decode(encoded)
|
||||
}()
|
||||
% end
|
||||
|
||||
%{
|
||||
# custom example: static let myVariable = "${os.environ.get('MY_CUSTOM_VARIABLE')}"
|
||||
}%
|
||||
|
||||
private let salt: [UInt8] = [
|
||||
% for chunk in chunks(salt, 8):
|
||||
${"".join(["0x%02x, " % byte for byte in chunk])}
|
||||
% end
|
||||
]
|
||||
|
||||
private func decode(_ encoded: [UInt8], salt: [UInt8]) -> String {
|
||||
String(decoding: encoded.enumerated().map { (offset, element) in
|
||||
element ^ salt[offset % salt.count]
|
||||
}, as: UTF8.self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private let salt: [UInt8] = [
|
||||
% for chunk in chunks(salt, 8):
|
||||
${"".join(["0x%02x, " % byte for byte in chunk])}
|
||||
% end
|
||||
]
|
||||
|
||||
private func decode(_ encoded: [UInt8]) -> String {
|
||||
String(decoding: encoded.enumerated().map { (offset, element) in
|
||||
element ^ salt[offset % salt.count]
|
||||
}, as: UTF8.self)
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
//
|
||||
// SecretsManager.swift
|
||||
//
|
||||
//
|
||||
// Created by Maurice Parker on 7/30/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class SecretsManager {
|
||||
public static var provider: SecretsProvider!
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
//
|
||||
// SecretsProvider.swift
|
||||
//
|
||||
//
|
||||
// Created by Maurice Parker on 7/30/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol SecretsProvider {
|
||||
var mercuryClientId: String { get }
|
||||
var mercuryClientSecret: String { get }
|
||||
var feedlyClientId: String { get }
|
||||
var feedlyClientSecret: String { get }
|
||||
var inoreaderAppId: String { get }
|
||||
var inoreaderAppKey: String { get }
|
||||
}
|
@ -38,8 +38,8 @@ class ArticleExtractor {
|
||||
self.articleLink = articleLink
|
||||
|
||||
let clientURL = "https://extract.feedbin.com/parser"
|
||||
let username = SecretsManager.provider.mercuryClientId
|
||||
let signature = articleLink.hmacUsingSHA1(key: SecretsManager.provider.mercuryClientSecret)
|
||||
let username = SecretKey.mercuryClientID
|
||||
let signature = articleLink.hmacUsingSHA1(key: SecretKey.mercuryClientSecret)
|
||||
|
||||
if let base64URL = articleLink.data(using: .utf8)?.base64EncodedString() {
|
||||
let fullURL = "\(clientURL)/\(username)/\(signature)?base64_url=\(base64URL)"
|
||||
|
Loading…
x
Reference in New Issue
Block a user