Refactor how we do Secrets to work with the new Swift Package structure

This commit is contained in:
Maurice Parker 2020-07-30 17:40:45 -05:00
parent 7bd1ac2d89
commit b724658528
16 changed files with 79 additions and 24 deletions

View File

@ -266,7 +266,7 @@ public final class RedditFeedProvider: FeedProvider {
extension RedditFeedProvider: OAuth2SwiftProvider {
public static var oauth2Swift: OAuth2Swift {
let oauth2 = OAuth2Swift(consumerKey: Secrets.redditConsumerKey,
let oauth2 = OAuth2Swift(consumerKey: SecretsManager.provider.redditConsumerKey,
consumerSecret: "",
authorizeUrl: "https://www.reddit.com/api/v1/authorize.compact?",
accessTokenUrl: "https://www.reddit.com/api/v1/access_token",
@ -283,7 +283,7 @@ extension RedditFeedProvider: OAuth2SwiftProvider {
let state = generateState(withLength: 20)
let scope = "identity mysubreddits read"
let params = [
"client_id" : Secrets.redditConsumerKey,
"client_id" : SecretsManager.provider.redditConsumerKey,
"response_type" : "code",
"state" : state,
"redirect_uri" : "netnewswire://success",

View File

@ -74,8 +74,8 @@ public final class TwitterFeedProvider: FeedProvider {
let tokenSecretCredentials = Credentials(type: .oauthAccessTokenSecret, username: screenName, secret: oauthTokenSecret)
try? CredentialsManager.storeCredentials(tokenSecretCredentials, server: Self.server)
client = OAuthSwiftClient(consumerKey: Secrets.twitterConsumerKey,
consumerSecret: Secrets.twitterConsumerSecret,
client = OAuthSwiftClient(consumerKey: SecretsManager.provider.twitterConsumerKey,
consumerSecret: SecretsManager.provider.twitterConsumerSecret,
oauthToken: oauthToken,
oauthTokenSecret: oauthTokenSecret,
version: .oauth1)
@ -92,8 +92,8 @@ public final class TwitterFeedProvider: FeedProvider {
self.oauthToken = tokenCredentials.secret
self.oauthTokenSecret = tokenSecretCredentials.secret
client = OAuthSwiftClient(consumerKey: Secrets.twitterConsumerKey,
consumerSecret: Secrets.twitterConsumerSecret,
client = OAuthSwiftClient(consumerKey: SecretsManager.provider.twitterConsumerKey,
consumerSecret: SecretsManager.provider.twitterConsumerSecret,
oauthToken: oauthToken,
oauthTokenSecret: oauthTokenSecret,
version: .oauth1)
@ -286,8 +286,8 @@ extension TwitterFeedProvider: OAuth1SwiftProvider {
public static var oauth1Swift: OAuth1Swift {
return OAuth1Swift(
consumerKey: Secrets.twitterConsumerKey,
consumerSecret: Secrets.twitterConsumerSecret,
consumerKey: SecretsManager.provider.twitterConsumerKey,
consumerSecret: SecretsManager.provider.twitterConsumerSecret,
requestTokenUrl: "https://api.twitter.com/oauth/request_token",
authorizeUrl: "https://api.twitter.com/oauth/authorize",
accessTokenUrl: "https://api.twitter.com/oauth/access_token"

View File

@ -11,7 +11,6 @@ import Secrets
enum FeedWranglerConfig {
static let pageSize = 100
static let clientKey = Secrets.feedWranglerKey // Add FEED_WRANGLER_KEY = XYZ to SharedXcodeSettings/DeveloperSettings.xcconfig
static let clientPath = "https://feedwrangler.net/api/v2/"
static let clientURL = {
URL(string: FeedWranglerConfig.clientPath)!

View File

@ -15,10 +15,10 @@ extension OAuthAuthorizationClient {
/// Models private NetNewsWire client secrets.
/// These placeholders are substitued 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: Secrets.feedlyClientId,
return OAuthAuthorizationClient(id: SecretsManager.provider.feedlyClientId,
redirectUri: "netnewswire://auth/feedly",
state: nil,
secret: Secrets.feedlyClientSecret)
secret: SecretsManager.provider.feedlyClientSecret)
}
static var feedlySandboxClient: OAuthAuthorizationClient {

View File

@ -30,7 +30,7 @@ public extension URLRequest {
self.url = url.appendingQueryItems([
URLQueryItem(name: "email", value: credentials.username),
URLQueryItem(name: "password", value: credentials.secret),
URLQueryItem(name: "client_key", value: FeedWranglerConfig.clientKey)
URLQueryItem(name: "client_key", value: SecretsManager.provider.feedWranglerKey)
])
case .feedWranglerToken:
self.url = url.appendingQueryItem(URLQueryItem(name: "access_token", value: credentials.secret))

View File

@ -14,6 +14,7 @@ import RSWeb
import Account
import RSCore
import RSCoreResources
import Secrets
// If we're not going to import Sparkle, provide dummy protocols to make it easy
// for AppDelegate to comply
@ -104,6 +105,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
NSWindow.allowsAutomaticWindowTabbing = false
super.init()
SecretsManager.provider = Secrets()
AccountManager.shared = AccountManager(accountsFolder: Platform.dataSubfolder(forApplication: nil, folderName: "Accounts")!)
FeedProviderManager.shared.delegate = ExtensionPointManager.shared

View File

@ -12,6 +12,7 @@ import RSWeb
import Account
import BackgroundTasks
import os.log
import Secrets
var appDelegate: AppDelegate!
@ -60,6 +61,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
super.init()
appDelegate = self
SecretsManager.provider = Secrets()
let documentAccountURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let documentAccountsFolder = documentAccountURL.appendingPathComponent("Accounts").absoluteString
let documentAccountsFolderPath = String(documentAccountsFolder.suffix(from: documentAccountsFolder.index(documentAccountsFolder.startIndex, offsetBy: 7)))

View File

@ -13,6 +13,7 @@ import Articles
import RSWeb
import Account
import RSCore
import Secrets
// If we're not going to import Sparkle, provide dummy protocols to make it easy
// for AppDelegate to comply
@ -70,6 +71,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
override init() {
super.init()
SecretsManager.provider = Secrets()
AccountManager.shared = AccountManager(accountsFolder: Platform.dataSubfolder(forApplication: nil, folderName: "Accounts")!)
FeedProviderManager.shared.delegate = ExtensionPointManager.shared

View File

@ -444,6 +444,12 @@
51C452AF2265108300C03939 /* ArticleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F204DF1FAACBB30076E152 /* ArticleArray.swift */; };
51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; };
51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; };
51C4CFF024D37D1F00AF9874 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4CFEF24D37D1F00AF9874 /* Secrets.swift */; };
51C4CFF124D37D1F00AF9874 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4CFEF24D37D1F00AF9874 /* Secrets.swift */; };
51C4CFF224D37D1F00AF9874 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4CFEF24D37D1F00AF9874 /* Secrets.swift */; };
51C4CFF324D37D1F00AF9874 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4CFEF24D37D1F00AF9874 /* Secrets.swift */; };
51C4CFF424D37D1F00AF9874 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4CFEF24D37D1F00AF9874 /* Secrets.swift */; };
51C4CFF624D37DD500AF9874 /* Secrets in Frameworks */ = {isa = PBXBuildFile; productRef = 51C4CFF524D37DD500AF9874 /* Secrets */; };
51C65AFC24CCB2C9008EB3BD /* TimelineItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */; };
51C65AFD24CCB2C9008EB3BD /* TimelineItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */; };
51C9DE5823EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */; };
@ -1661,6 +1667,7 @@
51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = "<group>"; };
51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = "<group>"; };
51C4CFEF24D37D1F00AF9874 /* Secrets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Secrets.swift; sourceTree = "<group>"; };
51C65AFB24CCB2C9008EB3BD /* TimelineItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItems.swift; sourceTree = "<group>"; };
51C9DE5723EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrapperScriptMessageHandler.swift; sourceTree = "<group>"; };
51CD32A824D2CB25009ABAEF /* SyncDatabase */ = {isa = PBXFileReference; lastKnownFileType = folder; path = SyncDatabase; sourceTree = "<group>"; };
@ -2043,6 +2050,7 @@
514C16DE24D2EF15009A3AFA /* RSTree in Frameworks */,
65ED42DE235E74230081F399 /* Sparkle.framework in Frameworks */,
65ED42D9235E740D0081F399 /* Sparkle.framework in Frameworks */,
51C4CFF624D37DD500AF9874 /* Secrets in Frameworks */,
51E4DAED2425F6940091EB5B /* CloudKit.framework in Frameworks */,
514C16E124D2EF38009A3AFA /* RSCoreResources in Frameworks */,
514C16CE24D2E63F009A3AFA /* Account in Frameworks */,
@ -3190,6 +3198,7 @@
isa = PBXGroup;
children = (
842E45CD1ED8C308000A8B52 /* AppNotifications.swift */,
51C4CFEF24D37D1F00AF9874 /* Secrets.swift */,
511B9805237DCAC90028BCAA /* UserInfoKey.swift */,
51C452AD2265102800C03939 /* Timeline */,
84702AB31FA27AE8006B8943 /* Commands */,
@ -3702,6 +3711,7 @@
514C16CD24D2E63F009A3AFA /* Account */,
514C16DD24D2EF15009A3AFA /* RSTree */,
514C16E024D2EF38009A3AFA /* RSCoreResources */,
51C4CFF524D37DD500AF9874 /* Secrets */,
);
productName = NetNewsWire;
productReference = 849C64601ED37A5D003D8FC0 /* NetNewsWire.app */;
@ -4420,6 +4430,7 @@
51B80EB824BD1F8B00C6C32D /* ActivityViewController.swift in Sources */,
51E4994224A8713C00B667CB /* ArticleStatusSyncTimer.swift in Sources */,
51E498F624A8085D00B667CB /* SearchFeedDelegate.swift in Sources */,
51C4CFF324D37D1F00AF9874 /* Secrets.swift in Sources */,
51B80EE124BD3E9600C6C32D /* FindInArticleActivity.swift in Sources */,
6586A5F724B632F8002BCF4F /* SettingsDetailAccountModel.swift in Sources */,
51E498F224A8085D00B667CB /* SmartFeedsController.swift in Sources */,
@ -4625,6 +4636,7 @@
51B54A4324B5499B0014348B /* WebViewProvider.swift in Sources */,
1799E6CE24C320D600511E91 /* InspectorModel.swift in Sources */,
514E6C0024AD255D00AC6F6E /* PreviewArticles.swift in Sources */,
51C4CFF424D37D1F00AF9874 /* Secrets.swift in Sources */,
1729529524AA1CAA00D65E66 /* GeneralPreferencesView.swift in Sources */,
1769E32724BC5B6C000E1E8E /* AddAccountModel.swift in Sources */,
1729529424AA1CAA00D65E66 /* AdvancedPreferencesView.swift in Sources */,
@ -4803,6 +4815,7 @@
65ED403C235DEF6C0081F399 /* SingleLineTextFieldSizer.swift in Sources */,
65ED403D235DEF6C0081F399 /* TimelineTableCellView.swift in Sources */,
65ED403E235DEF6C0081F399 /* TimelineCellAppearance.swift in Sources */,
51C4CFF124D37D1F00AF9874 /* Secrets.swift in Sources */,
510C43F4243C11FE009F70C3 /* ExtensionPointAddTableCellView.swift in Sources */,
65ED403F235DEF6C0081F399 /* ArticleRenderer.swift in Sources */,
65ED4040235DEF6C0081F399 /* GeneralPrefencesViewController.swift in Sources */,
@ -4888,6 +4901,7 @@
5F323809231DF9F000706F6B /* VibrantTableViewCell.swift in Sources */,
51FE10042345529D0056195D /* UserNotificationManager.swift in Sources */,
519ED47C24488C6F007F8E94 /* ExtensionInspectorViewController.swift in Sources */,
51C4CFF224D37D1F00AF9874 /* Secrets.swift in Sources */,
51C452A022650A1900C03939 /* WebFeedIconDownloader.swift in Sources */,
51C4529E22650A1900C03939 /* ImageDownloader.swift in Sources */,
51A66685238075AE00CB272D /* AddWebFeedDefaultContainer.swift in Sources */,
@ -5140,6 +5154,7 @@
84B99C9D1FAE83C600ECDEDB /* DeleteCommand.swift in Sources */,
849A97541ED9EAC0007D329B /* AddWebFeedWindowController.swift in Sources */,
5144EA40227A37EC00D19003 /* ImportOPMLWindowController.swift in Sources */,
51C4CFF024D37D1F00AF9874 /* Secrets.swift in Sources */,
849A976D1ED9EBC8007D329B /* TimelineTableView.swift in Sources */,
51333D1624685D2E00EB5C91 /* AddRedditFeedWindowController.swift in Sources */,
84D52E951FE588BB00D14F5B /* DetailStatusBarView.swift in Sources */,
@ -5782,6 +5797,10 @@
package = 510ECA4024D1DCD0001C31A6 /* XCRemoteSwiftPackageReference "RSTree" */;
productName = RSTree;
};
51C4CFF524D37DD500AF9874 /* Secrets */ = {
isa = XCSwiftPackageProductDependency;
productName = Secrets;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 849C64581ED37A5D003D8FC0 /* Project object */;

View File

@ -10,7 +10,7 @@
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "&quot;${PROJECT_DIR}/buildscripts/updateSecrets.sh&quot;&#10;">
scriptText = "&quot;${PROJECT_DIR}/buildscripts/updateSecrets.sh&quot; 2&gt;&amp;1&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"

View File

@ -17,7 +17,6 @@ let package = Package(
name: "Secrets",
dependencies: [
.product(name: "OAuthSwift", package: "OAuthSwift"),
],
exclude: ["Secrets.swift.gyb"]),
]),
]
)

View File

@ -0,0 +1,12 @@
//
// SecretsManager.swift
//
//
// Created by Maurice Parker on 7/30/20.
//
import Foundation
public class SecretsManager {
public static var provider: SecretsProvider!
}

View File

@ -0,0 +1,19 @@
//
// SecretsProvider.swift
//
//
// Created by Maurice Parker on 7/30/20.
//
import Foundation
public protocol SecretsProvider {
var feedWranglerKey: String { get }
var mercuryClientId: String { get }
var mercuryClientSecret: String { get }
var feedlyClientId: String { get }
var feedlyClientSecret: String { get }
var twitterConsumerKey: String { get }
var twitterConsumerSecret: String { get }
var redditConsumerKey: String { get }
}

View File

@ -38,8 +38,8 @@ class ArticleExtractor {
self.articleLink = articleLink
let clientURL = "https://extract.feedbin.com/parser"
let username = Secrets.mercuryClientId
let signiture = articleLink.hmacUsingSHA1(key: Secrets.mercuryClientSecret)
let username = SecretsManager.provider.mercuryClientId
let signiture = articleLink.hmacUsingSHA1(key: SecretsManager.provider.mercuryClientSecret)
if let base64URL = articleLink.data(using: .utf8)?.base64EncodedString() {
let fullURL = "\(clientURL)/\(username)/\(signiture)?base64_url=\(base64URL)"

View File

@ -17,10 +17,12 @@ def snake_to_camel(snake_str):
salt = [ord(byte) for byte in os.urandom(64)]
}%
public enum Secrets {
import Secrets
public struct Secrets: SecretsProvider {
% for secret in secrets:
public static var ${snake_to_camel(secret)}: String {
public var ${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])}
@ -34,17 +36,14 @@ public enum Secrets {
%{
# custom example: static let myVariable = "${os.environ.get('MY_CUSTOM_VARIABLE')}"
}%
}
private extension Secrets {
private static let salt: [UInt8] = [
private let salt: [UInt8] = [
% for chunk in chunks(salt, 8):
${"".join(["0x%02x, " % byte for byte in chunk])}
% end
]
private static func decode(_ encoded: [UInt8], salt: [UInt8]) -> String {
private func decode(_ encoded: [UInt8], salt: [UInt8]) -> String {
String(decoding: encoded.enumerated().map { (offset, element) in
element ^ salt[offset % salt.count]
}, as: UTF8.self)

View File

@ -12,6 +12,7 @@ import RSWeb
import Account
import BackgroundTasks
import os.log
import Secrets
var appDelegate: AppDelegate!
@ -60,6 +61,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
super.init()
appDelegate = self
SecretsManager.provider = Secrets()
let documentAccountURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let documentAccountsFolder = documentAccountURL.appendingPathComponent("Accounts").absoluteString
let documentAccountsFolderPath = String(documentAccountsFolder.suffix(from: documentAccountsFolder.index(documentAccountsFolder.startIndex, offsetBy: 7)))