-
Notifications
You must be signed in to change notification settings - Fork 3
Add Login Spec #532
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Login Spec #532
Conversation
a87e570
to
b351665
Compare
68c4b18
to
bc249b1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkmassel I've left some comments about the Rust implementation. I haven't reviewed the documentation or the Swift changes yet.
|
||
Reference Implementation: http://localhost | ||
|
||
# 3: WordPress Admin URL Entry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This says WordPress Admin
, but it handles both /wp-login
and wp-admin
cases, should we rename it?
cd36fa5
to
b35616a
Compare
f394028
to
7e0c993
Compare
4db0bf9
to
c1983be
Compare
82ec5ab
to
19ebcb2
Compare
1de057f
to
17c1c30
Compare
5c612dd
to
cf435e4
Compare
8343090
to
8ec93da
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the Rust API comments, I tried to make the changes myself. But as I was making changes to them, it came to me that you guys may have tried that already. So, I haven't gone too deep into them, but I'm happy to make some proof of concept changes if needed.
@@ -17,3 +17,23 @@ public extension Date { | |||
wordpressDateFormatter.date(from: string) | |||
} | |||
} | |||
|
|||
public extension TimeInterval { | |||
static func fromRetryHeaderValue(_ value: String, now: Date = Date()) -> TimeInterval? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function does not seem to be used anywhere except unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed in 8e99aa7 – this was moved to Rust!
|
||
private func fetch(request: URLRequest) async throws -> (Data, URLResponse) { | ||
if #available(macOS 12.0, *) { | ||
return try await self.session.data(for: request, delegate: executorDelegate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is available on all Apple platforms. Maybe we can change this function to be something like this?
#if os(Linux)
return session.data(for: request)
#else
return session.data(for: request, delegate: executorDelegate)
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 23fdee9 – this was because all the development happened on macOS
} | ||
|
||
private func getPeerCertificateChain(_ error: Error) throws -> [SSLCertificateInfo] { | ||
private func getPeerCertificateChain(_ error: Error) -> [SSLCertificateInfo]? { | ||
let nserror = error as NSError | ||
let info = nserror.userInfo | ||
|
||
guard let certChainArray = info["NSErrorPeerCertificateChainKey"] as? NSArray else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the parseCertificateChain
function below if changing this casting statement to info["NSErrorPeerCertificateChainKey"] as? [SecCertificate]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Done in c07115c
forSite proposedSiteUrl: String | ||
) async throws(AutoDiscoveryAttemptFailure) -> AutoDiscoveryAttemptResult { | ||
|
||
let discoveryResult = await client.apiDiscovery(siteUrl: proposedSiteUrl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change this function to fn api_discovery(&self, site_url: String) -> Result<Arc<AutoDiscoveryAttemptSuccess>, AutoDiscoveryAttemptFailure>
and do the if-else checks below within Rust?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function currently returns AutoDiscoveryResult/AutoDiscoveryUniffiResult
which is the result of combination of multiple attempts, so this suggestion wouldn't work. Happy to elaborate on it if you need more details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I'd love more details.
I haven't looked the how Kotlin uses the api_discovery
function. But the Swift function here turns the AutoDiscoveryUniffiResult
into either a success result or a failure, which essentially is Result<Arc<AutoDiscoveryAttemptSuccess>, AutoDiscoveryAttemptFailure>
.
|
||
init( | ||
urlSession: URLSession, | ||
additionalHttpHeadersForAllRequests: [String: String] = [:] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This argument is not used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not by our code, but this is a good back-door way to add a user agent (for instance).
Should that just be a separate PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same feature can be achieved using URLSession
. But I guess this argument would allow adding headers only for API requests originated from the library. I'm okay with it being in this PR if it's needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm hoping we can limit the number of things that a developer has to handle themselves in URLSession
, but I guess we'll see?
import FoundationNetworking | ||
#endif | ||
|
||
public final class WordPressLoginClient { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, there is not much going on in this type. Can we use UniffiWpLoginClient
directly? You'll need to add the loginURL(...)
and credentials(...)
helper functions to it, but I don't think that's a terrible thing to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be fine if we get there eventually, but the name is wrong – nobody consuming this library should ever see UniffiWpLoginClient
. At the very least we'll have to typealias it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't finished the review yet, but I left some pretty important comments about the Kotlin implementation which may affect the remaining files I haven't reviewed yet.
P.S: I usually review my comments before posting, but I am not able to do that at the moment and don't want to risk losing them. So, if there is anything poorly worded or plain incorrect, I apologize in advance as it was unintentional.
native/kotlin/build.gradle.kts
Outdated
|
||
tasks.register<Copy>("copySampleJSON") { | ||
dependsOn(tasks.named("deleteTestResources")) | ||
from("$cargoProjectRoot/native/swift/Tests/wordpress-api/Resources/Responses/localhost-json-root.json") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably best to put this somewhere in the native
directory, rather than under swift
or kotlin
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say let's do this as soon as we have a second item
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/MockRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt
Outdated
Show resolved
Hide resolved
native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpLoginClient.kt
Outdated
Show resolved
Hide resolved
func testNotWordPressSite() async throws { | ||
let client = WordPressLoginClient(urlSession: .shared) | ||
await #expect(performing: { | ||
_ = try await client.findLoginUrl(forSite: "https://google.com") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the input is "google.com", the returned error is ParseUrlError.RelativeUrlWithoutBase
. IMO that's an incorrect error. I'd expect the error to be probablyNotAWordPressSite
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested this in Rust with the new combinedResult
function from #652 and it returned ProbablyNotAWordPressSite
as expected. Once this PR is updated, the issue should be resolved for Swift as well.
// Full error message for `google.com`
FindApiRoot {
parsed_site_url: ParsedUrl {
inner: Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"google.com",
),
),
port: None,
path: "/",
query: None,
fragment: None,
},
},
find_api_root_failure: ProbablyNotAWordPressSite,
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkmassel Do you mind adding google.com
as a test case, which should be fairly easy with @Test(arguments: ["google.com", "https://google.com"])
?
8ec93da
to
e8a1e3e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a couple of minor comments.
|
||
public protocol AuthenticatorProtocol { | ||
func authenticate(url: URL, callbackURL: URL) async throws -> URL | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This protocol can be removed.
We moved pretty much all the Kotlin stuff to #655
As discussed with @oguzkocer – there are a lot of different things that can happen during login, so let's document them so we can ensure we're testing them for each HTTP implementation (the native Rust one, Apple platforms'
URLSession
, and Android)