Skip to content

Commit 3a42b31

Browse files
committed
WIP Reddit Oauth
1 parent 6f5d225 commit 3a42b31

File tree

10 files changed

+164
-2
lines changed

10 files changed

+164
-2
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,4 @@ fastlane/test_output
8888
# https://github.com/johnno1962/injectionforxcode
8989

9090
iOSInjectionProject/
91+
Packages/Backend/Sources/Backend/Resources/secrets.plist

Packages/Backend/Package.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ let package = Package(
1313
name: "Backend",
1414
targets: ["Backend"]),
1515
],
16+
dependencies: [
17+
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.0"),
18+
],
1619
targets: [
1720
.target(
1821
name: "Backend",
19-
dependencies: []),
22+
dependencies: ["KeychainAccess"],
23+
resources: [.process("Resources")]),
2024
.testTarget(
2125
name: "BackendTests",
2226
dependencies: ["Backend"]),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import SwiftUI
2+
import Combine
3+
import Foundation
4+
import KeychainAccess
5+
6+
7+
public class OauthClient: ObservableObject {
8+
public enum State {
9+
case unknown, signedOut, signinInProgress, authenthicated(authToken: String)
10+
}
11+
12+
@Published public var authState = State.unknown
13+
14+
// Oauth URL
15+
private let baseURL = "https://www.reddit.com/api/v1/authorize"
16+
private let secrets: [String: AnyObject]?
17+
private let scopes = ["mysubreddits", "identity", "edit", "save", "vote", "subscribe", "read", "submit"]
18+
private let state = UUID().uuidString
19+
private let redirectURI = "redditos://auth"
20+
private let duration = "permanent"
21+
private let type = "code"
22+
23+
// Keychain
24+
private let keychainService = "com.thomasricouard.RedditOs-reddit-token"
25+
private let keychainAuthTokenKey = "auth_token"
26+
27+
public init() {
28+
if let path = Bundle.module.path(forResource: "secrets", ofType: "plist"),
29+
let secrets = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
30+
self.secrets = secrets
31+
} else {
32+
self.secrets = nil
33+
print("Error: No secrets file found, you won't be able to login on Reddit")
34+
}
35+
36+
let keychain = Keychain(service: keychainService)
37+
if let token = keychain[keychainAuthTokenKey] {
38+
authState = .authenthicated(authToken: token)
39+
} else {
40+
authState = .signedOut
41+
}
42+
}
43+
44+
public func startOauthFlow() -> URL? {
45+
guard let clientId = secrets?["client_id"] as? String else {
46+
return nil
47+
}
48+
49+
authState = .signinInProgress
50+
51+
return URL(string: baseURL)!
52+
.appending("client_id", value: clientId)
53+
.appending("response_type", value: type)
54+
.appending("state", value: state)
55+
.appending("redirect_uri", value: redirectURI)
56+
.appending("duration", value: duration)
57+
.appending("scope", value: scopes.joined(separator: " "))
58+
}
59+
60+
public func handleNextURL(url: URL) {
61+
authState = .signinInProgress
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is compiled as part of the Backend package. In order to make the Oauth work from the open source clone of this project you would need to create a secrets.plist with a client_id key and your Reddit app client id as value in this folder.

RedditOs.xcodeproj/project.pbxproj

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
692566D624B8A25A0014E0D4 /* PostDetailContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692566D524B8A25A0014E0D4 /* PostDetailContent.swift */; };
1212
692566D824B8A3190014E0D4 /* PostDetailActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692566D724B8A3190014E0D4 /* PostDetailActions.swift */; };
1313
692566DA24B8A3830014E0D4 /* PostDetailHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692566D924B8A3830014E0D4 /* PostDetailHeader.swift */; };
14+
6927894924B9B75200EEFBF2 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6927894824B9B75200EEFBF2 /* ProfileView.swift */; };
1415
6970A0AE24B74A9D00B11031 /* ListingInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6970A0AD24B74A9D00B11031 /* ListingInfoView.swift */; };
1516
6970A0B124B74B7900B11031 /* SDWebImageSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 6970A0B024B74B7900B11031 /* SDWebImageSwiftUI */; };
1617
6970A0B324B77D1200B11031 /* ListingVoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6970A0B224B77D1200B11031 /* ListingVoteView.swift */; };
@@ -37,6 +38,7 @@
3738
692566D524B8A25A0014E0D4 /* PostDetailContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostDetailContent.swift; sourceTree = "<group>"; };
3839
692566D724B8A3190014E0D4 /* PostDetailActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostDetailActions.swift; sourceTree = "<group>"; };
3940
692566D924B8A3830014E0D4 /* PostDetailHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostDetailHeader.swift; sourceTree = "<group>"; };
41+
6927894824B9B75200EEFBF2 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
4042
6970A0AD24B74A9D00B11031 /* ListingInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingInfoView.swift; sourceTree = "<group>"; };
4143
6970A0B224B77D1200B11031 /* ListingVoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingVoteView.swift; sourceTree = "<group>"; };
4244
6970A0B524B783FE00B11031 /* LinkPresentationRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPresentationRepresentable.swift; sourceTree = "<group>"; };
@@ -73,6 +75,14 @@
7375
/* End PBXFrameworksBuildPhase section */
7476

7577
/* Begin PBXGroup section */
78+
6927894724B9B74900EEFBF2 /* Profile */ = {
79+
isa = PBXGroup;
80+
children = (
81+
6927894824B9B75200EEFBF2 /* ProfileView.swift */,
82+
);
83+
path = Profile;
84+
sourceTree = "<group>";
85+
};
7686
6970A0AC24B7494C00B11031 /* Shared */ = {
7787
isa = PBXGroup;
7888
children = (
@@ -152,6 +162,7 @@
152162
69EACF2024B7298C00303A16 /* Features */ = {
153163
isa = PBXGroup;
154164
children = (
165+
6927894724B9B74900EEFBF2 /* Profile */,
155166
6970A0B724B79AF400B11031 /* Search */,
156167
69EACF2124B7299000303A16 /* Sidebar */,
157168
69EACF2324B73D6900303A16 /* Post */,
@@ -280,6 +291,7 @@
280291
6970A0BB24B79F5900B11031 /* SearchSubredditsViewModel.swift in Sources */,
281292
6906880D24B743900067D973 /* SubredditPostRow.swift in Sources */,
282293
69EACF1F24B7298800303A16 /* SidebarViewModel.swift in Sources */,
294+
6927894924B9B75200EEFBF2 /* ProfileView.swift in Sources */,
283295
69EACF1724B6F2BA00303A16 /* PostDetail.swift in Sources */,
284296
692566D824B8A3190014E0D4 /* PostDetailActions.swift in Sources */,
285297
69EACF0324B63D5800303A16 /* RedditOsApp.swift in Sources */,

RedditOs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{
22
"object": {
33
"pins": [
4+
{
5+
"package": "KeychainAccess",
6+
"repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess",
7+
"state": {
8+
"branch": null,
9+
"revision": "3d0ea2c0806791abcc5d7f0d9f62f1cfd4a7264d",
10+
"version": "4.2.0"
11+
}
12+
},
413
{
514
"package": "SDWebImage",
615
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// ProfileView.swift
3+
// RedditOs
4+
//
5+
// Created by Thomas Ricouard on 11/07/2020.
6+
//
7+
8+
import SwiftUI
9+
import Backend
10+
11+
struct ProfileView: View {
12+
@EnvironmentObject private var oauthClient: OauthClient
13+
@Environment(\.openURL) private var openURL
14+
15+
var body: some View {
16+
VStack {
17+
Spacer()
18+
HStack {
19+
Spacer()
20+
switch oauthClient.authState {
21+
case .signedOut:
22+
Button {
23+
if let url = oauthClient.startOauthFlow() {
24+
openURL(url)
25+
}
26+
} label: {
27+
Text("Sign in")
28+
}
29+
case .signinInProgress:
30+
ProgressView("Auth in progress")
31+
case .authenthicated:
32+
Text("Signed in")
33+
case .unknown:
34+
Text("Error")
35+
}
36+
Spacer()
37+
}
38+
Spacer()
39+
}.frame(minWidth: 400, minHeight: 500)
40+
}
41+
}
42+
43+
struct ProfileView_Previews: PreviewProvider {
44+
static var previews: some View {
45+
ProfileView()
46+
}
47+
}

RedditOs/Features/Sidebar/Sidebar.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ struct Sidebar: View {
2626

2727
Group {
2828
Text("Account").foregroundColor(.white)
29-
Label("Profile", systemImage: "person.crop.square")
29+
NavigationLink(destination: ProfileView()) {
30+
Label("Profile", systemImage: "person.crop.square")
31+
}.tag("profile")
3032
Label("Inbox", systemImage: "envelope")
3133
Label("Posts", systemImage: "square.and.pencil")
3234
Label("Comments", systemImage: "bubble.middle.bottom.fill")

RedditOs/Info.plist

+13
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@
1616
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1717
<key>CFBundleShortVersionString</key>
1818
<string>1.0</string>
19+
<key>CFBundleURLTypes</key>
20+
<array>
21+
<dict>
22+
<key>CFBundleTypeRole</key>
23+
<string>Editor</string>
24+
<key>CFBundleURLName</key>
25+
<string>redditos</string>
26+
<key>CFBundleURLSchemes</key>
27+
<array>
28+
<string>redditos</string>
29+
</array>
30+
</dict>
31+
</array>
1932
<key>CFBundleVersion</key>
2033
<string>1</string>
2134
<key>LSMinimumSystemVersion</key>

RedditOs/RedditOsApp.swift

+10
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@
55
// Created by Thomas Ricouard on 08/07/2020.
66
//
77

8+
import AppKit
89
import SwiftUI
910
import Backend
1011

12+
class AppDelegateAdaptor: NSObject, NSApplicationDelegate {
13+
func application(_ application: NSApplication, open urls: [URL]) {
14+
15+
}
16+
}
17+
18+
1119
@main
1220
struct RedditOsApp: App {
21+
@NSApplicationDelegateAdaptor(AppDelegateAdaptor.self) private var appDelegate
1322

1423
@SceneBuilder
1524
var body: some Scene {
@@ -23,6 +32,7 @@ struct RedditOsApp: App {
2332
}
2433
.frame(minHeight: 400)
2534
.environmentObject(PersistedContent())
35+
.environmentObject(OauthClient())
2636
}
2737

2838
Settings {

0 commit comments

Comments
 (0)