Skip to content

Commit 4cad464

Browse files
committed
implement github social login flow
1 parent 98309db commit 4cad464

File tree

239 files changed

+4396
-277
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

239 files changed

+4396
-277
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
.unidoc
55
.vscode
66

7+
Assets/secrets/
78
TestDeployment/data/
89

910
node_modules/

Assets/js/Main.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/js/Main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.resolved

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ let package:Package = .init(
1414
.library(name: "DoclinkResolution", targets: ["DoclinkResolution"]),
1515
.library(name: "FNV1", targets: ["FNV1"]),
1616

17+
.library(name: "GitHubIntegration", targets: ["GitHubIntegration"]),
18+
1719
.library(name: "HTML", targets: ["HTML"]),
1820

21+
.library(name: "HTTPClient", targets: ["HTTPClient"]),
1922
.library(name: "HTTPServer", targets: ["HTTPServer"]),
2023

2124
.library(name: "LexicalPaths", targets: ["LexicalPaths"]),
@@ -24,7 +27,7 @@ let package:Package = .init(
2427
.library(name: "MarkdownParsing", targets: ["MarkdownParsing"]),
2528
.library(name: "MarkdownRendering", targets: ["MarkdownRendering"]),
2629
.library(name: "MarkdownSemantics", targets: ["MarkdownSemantics"]),
27-
.library(name: "MarkdownTrees", targets: ["MarkdownTrees"]),
30+
.library(name: "MarkdownAST", targets: ["MarkdownAST"]),
2831

2932
.library(name: "Media", targets: ["Media"]),
3033

@@ -51,6 +54,7 @@ let package:Package = .init(
5154
.library(name: "System", targets: ["System"]),
5255

5356
.library(name: "Unidoc", targets: ["Unidoc"]),
57+
.library(name: "UnidocAnalysis", targets: ["UnidocAnalysis"]),
5458
.library(name: "UnidocDatabase", targets: ["UnidocDatabase"]),
5559
.library(name: "UnidocDiagnostics", targets: ["UnidocDiagnostics"]),
5660
.library(name: "UnidocLinker", targets: ["UnidocLinker"]),
@@ -64,15 +68,17 @@ let package:Package = .init(
6468
],
6569
dependencies:
6670
[
67-
.package(url: "https://github.com/tayloraswift/swift-json", .upToNextMinor(
68-
from: "0.6.0")),
71+
//.package(url: "https://github.com/tayloraswift/swift-json", .upToNextMinor(
72+
// from: "0.6.0")),
6973
.package(url: "https://github.com/tayloraswift/swift-grammar", .upToNextMinor(
7074
from: "0.3.2")),
7175
.package(url: "https://github.com/tayloraswift/swift-mongodb", .upToNextMinor(
7276
from: "0.7.2")),
7377

7478
.package(url: "https://github.com/apple/swift-nio", .upToNextMinor(
7579
from: "2.57.0")),
80+
.package(url: "https://github.com/apple/swift-nio-http2", .upToNextMinor(
81+
from: "1.27.0")),
7682
.package(url: "https://github.com/apple/swift-nio-ssl", .upToNextMinor(
7783
from: "2.24.0")),
7884
.package(url: "https://github.com/apple/swift-markdown", .upToNextMinor(
@@ -117,6 +123,12 @@ let package:Package = .init(
117123

118124
.target(name: "FNV1"),
119125

126+
.target(name: "GitHubIntegration", dependencies:
127+
[
128+
.target(name: "JSON"),
129+
.target(name: "HTTPClient"),
130+
]),
131+
120132
.target(name: "HTML", dependencies:
121133
[
122134
.target(name: "HTMLDOM"),
@@ -130,6 +142,17 @@ let package:Package = .init(
130142
.target(name: "HTMLDOM"),
131143
]),
132144

145+
.target(name: "HTTPClient", dependencies:
146+
[
147+
.target(name: "HTML"),
148+
.target(name: "Media"),
149+
.target(name: "MD5"),
150+
.product(name: "NIOHTTP1", package: "swift-nio"),
151+
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
152+
.product(name: "NIOSSL", package: "swift-nio-ssl"),
153+
.product(name: "TraceableErrors", package: "swift-grammar"),
154+
]),
155+
133156
.target(name: "HTTPServer", dependencies:
134157
[
135158
.target(name: "HTML"),
@@ -142,6 +165,37 @@ let package:Package = .init(
142165

143166
.target(name: "InlineBuffer"),
144167

168+
169+
.target(name: "JSONAST"),
170+
171+
.target(name: "JSONDecoding", dependencies:
172+
[
173+
.target(name: "JSONAST"),
174+
]),
175+
176+
.target(name: "JSONEncoding", dependencies:
177+
[
178+
.target(name: "JSONAST"),
179+
]),
180+
181+
.target(name: "JSONLegacy", dependencies:
182+
[
183+
.target(name: "JSONDecoding"),
184+
]),
185+
186+
.target(name: "JSONParsing", dependencies:
187+
[
188+
.target(name: "JSONAST"),
189+
.product(name: "Grammar", package: "swift-grammar"),
190+
]),
191+
192+
.target(name: "JSON", dependencies:
193+
[
194+
.target(name: "JSONDecoding"),
195+
.target(name: "JSONEncoding"),
196+
.target(name: "JSONParsing"),
197+
]),
198+
145199
.target(name: "LexicalPaths"),
146200

147201
.target(name: "MarkdownABI"),
@@ -152,15 +206,15 @@ let package:Package = .init(
152206
.target(name: "MarkdownABI"),
153207
]),
154208

155-
.target(name: "MarkdownTrees", dependencies:
209+
.target(name: "MarkdownAST", dependencies:
156210
[
157211
.target(name: "MarkdownABI"),
158212
.target(name: "Sources"),
159213
]),
160214

161215
.target(name: "MarkdownParsing", dependencies:
162216
[
163-
.target(name: "MarkdownTrees"),
217+
.target(name: "MarkdownAST"),
164218
// TODO: this links Foundation. Need to find a replacement.
165219
.product(name: "Markdown", package: "swift-markdown"),
166220
]),
@@ -175,7 +229,7 @@ let package:Package = .init(
175229
.target(name: "MarkdownSemantics", dependencies:
176230
[
177231
.target(name: "Codelinks"),
178-
.target(name: "MarkdownTrees"),
232+
.target(name: "MarkdownAST"),
179233
]),
180234

181235
.target(name: "MD5", dependencies:
@@ -204,10 +258,8 @@ let package:Package = .init(
204258

205259
.target(name: "PackageMetadata", dependencies:
206260
[
261+
.target(name: "JSON"),
207262
.target(name: "PackageGraphs"),
208-
209-
.product(name: "JSONDecoding", package: "swift-json"),
210-
.product(name: "JSONEncoding", package: "swift-json"),
211263
]),
212264

213265
.target(name: "SemanticVersions"),
@@ -262,13 +314,12 @@ let package:Package = .init(
262314

263315
.target(name: "SymbolGraphParts", dependencies:
264316
[
317+
.target(name: "JSON"),
265318
.target(name: "LexicalPaths"),
266319
.target(name: "ModuleGraphs"),
267320
.target(name: "Signatures"),
268321
.target(name: "Symbols"),
269322
.target(name: "Unidoc"),
270-
.product(name: "JSONDecoding", package: "swift-json"),
271-
.product(name: "JSONEncoding", package: "swift-json"),
272323
]),
273324

274325
.target(name: "SymbolGraphs", dependencies:
@@ -302,8 +353,9 @@ let package:Package = .init(
302353

303354
.target(name: "UnidocAnalysis", dependencies:
304355
[
305-
.target(name: "UnidocSelectors"),
356+
.target(name: "JSONEncoding"),
306357
.target(name: "MD5"),
358+
.target(name: "UnidocSelectors"),
307359
]),
308360

309361
.target(name: "UnidocDatabase", dependencies:
@@ -329,6 +381,7 @@ let package:Package = .init(
329381

330382
.target(name: "UnidocPages", dependencies:
331383
[
384+
.target(name: "GitHubIntegration"),
332385
.target(name: "HTTPServer"),
333386
.target(name: "MarkdownRendering"),
334387
.target(name: "UnidocQueries"),
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import HTTPClient
2+
import JSON
3+
import NIOCore
4+
import NIOHPACK
5+
6+
extension GitHubApplication
7+
{
8+
@frozen public
9+
struct Client
10+
{
11+
private
12+
let http2:ClientInterface
13+
public
14+
let app:GitHubApplication
15+
16+
public
17+
init(http2:ClientInterface, app:GitHubApplication)
18+
{
19+
self.http2 = http2
20+
self.app = app
21+
}
22+
}
23+
}
24+
extension GitHubApplication.Client
25+
{
26+
public
27+
func exchange(code:String) async -> Result<GitHubTokens, GitHubAuthenticationError>
28+
{
29+
let request:HPACKHeaders =
30+
[
31+
":method": "POST",
32+
":scheme": "https",
33+
":authority": "github.com",
34+
":path": """
35+
/login/oauth/access_token?\
36+
client_id=\(self.app.id)&client_secret=\(self.app.secret)&code=\(code)
37+
""",
38+
39+
"accept": "application/vnd.github+json",
40+
]
41+
42+
let response:ClientInterface.Facet
43+
do
44+
{
45+
response = try await self.http2.fetch(request)
46+
}
47+
catch let error
48+
{
49+
return .failure(.fetch(error))
50+
}
51+
52+
guard let headers:HPACKHeaders = response.headers,
53+
headers[canonicalForm: ":status"] == ["200"]
54+
else
55+
{
56+
return .failure(.status)
57+
}
58+
59+
var json:JSON = .init(utf8: [])
60+
for buffer:ByteBuffer in response.buffers
61+
{
62+
json.utf8 += buffer.readableBytesView
63+
}
64+
65+
do
66+
{
67+
return .success(try json.decode())
68+
}
69+
catch let error
70+
{
71+
return .failure(.response(error))
72+
}
73+
}
74+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import HTTPClient
2+
import JSON
3+
import NIOCore
4+
import NIOHPACK
5+
6+
@frozen public
7+
struct GitHubApplication:Identifiable, Equatable, Hashable, Sendable
8+
{
9+
public
10+
let secret:String
11+
public
12+
let id:String
13+
14+
@inlinable public
15+
init(_ id:String, secret:String = "3a892428d6381dbcfdafab55ad2fbec6d4847430")
16+
{
17+
self.id = id
18+
self.secret = secret
19+
}
20+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@frozen public
2+
enum GitHubAuthenticationError:Error, Sendable
3+
{
4+
case fetch(any Error)
5+
case status
6+
case response(any Error)
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@frozen public
2+
struct GitHubToken:Equatable, Hashable, Sendable
3+
{
4+
public
5+
let secondsRemaining:Int
6+
public
7+
let value:String
8+
9+
@inlinable public
10+
init(value:String, secondsRemaining:Int)
11+
{
12+
self.value = value
13+
self.secondsRemaining = secondsRemaining
14+
}
15+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import JSON
2+
3+
@frozen public
4+
struct GitHubTokens:Equatable, Hashable, Sendable
5+
{
6+
public
7+
let refresh:GitHubToken
8+
public
9+
let access:GitHubToken
10+
11+
@inlinable public
12+
init(refresh:GitHubToken, access:GitHubToken)
13+
{
14+
self.refresh = refresh
15+
self.access = access
16+
}
17+
}
18+
extension GitHubTokens:JSONObjectDecodable
19+
{
20+
public
21+
enum CodingKey:String
22+
{
23+
case access_value = "access_token"
24+
case access_secondsRemaining = "expires_in"
25+
case refresh_value = "refresh_token"
26+
case refresh_secondsRemaining = "refresh_token_expires_in"
27+
}
28+
29+
public
30+
init(json:JSON.ObjectDecoder<CodingKey>) throws
31+
{
32+
self.init(
33+
refresh: .init(value: try json[.refresh_value].decode(),
34+
secondsRemaining: try json[.refresh_secondsRemaining].decode()),
35+
access: .init(value: try json[.access_value].decode(),
36+
secondsRemaining: try json[.access_secondsRemaining].decode()))
37+
}
38+
}

0 commit comments

Comments
 (0)