-
Notifications
You must be signed in to change notification settings - Fork 3
Authorization Url Discovery #160
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
Conversation
// `test_credentials` file `make test-server` will generate in the root of the repo | ||
// It's the 3rd line in that file | ||
localTestSitePassword = "ncmRlxWjoaGdvMXyoXylhqGX" | ||
localTestSitePassword = "l4dvgr1UjuCKXiqkbdbXn1b5" |
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.
Will this be consistent between runs?
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.
Nope - the comment above localTestSitePassword
explains the situation. I need to take some time to move the current integration tests to the example module and make the test_credentials
file available to both the example app and the integration tests. I know how to do address it, but I need to spend time on it. Since this is low priority it's going to remain as such for a little while longer.
modifier = Modifier.fillMaxSize(), | ||
) { | ||
var siteUrl by remember { mutableStateOf("https://loudly-special.jurassic.ninja/") } | ||
var siteUrl by remember { mutableStateOf("boldly-inner.jurassic.ninja") } |
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.
Same question
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 is just to make it easier to run multiple tests without inputting the url each time. This input field would normally be left empty, but it's useful to have it populated for me during this active development stage.
I think we can add a user populated credentials file - or read it from gradle.properties
or something - so each developer can use their own site to populate the field. Similar to the other comment, I know how to address it, but I don't think I should prioritize it.
This PR implements url discovery for authorization. There are quite a few parts to get this all working:
HeaderMap
We have been postponing the handling of headers for a while now. We attempted to improve it in #132, but then had to revert it in #135 as it conflicted with an ongoing complicated refactor. I've had to address this in this PR as properly parsing the headers is one of the requirements for finding the authorization url.
The PR introduces a new
WpNetworkHeaderMap
type that wrapshttp::HeaderMap
. It provides ways to construct the type from aMap<String, String>
& aMap<String, Vec<String>>
. In both cases, the values are split by comma to multiple values, so this should accommodate all consumers. Rust consumers can directly construct this type fromHeaderMap
.The Kotlin wrapper and Rust integration tests are both updated to properly parse the response headers.
Note that
WpNetworkRequest
has not been updated to use this new type yet. Since that'd be an unrelated change - and this PR is complicated enough as is - I've left that to be addresses in a later PR.Separating Uniffi specific clients
This PR proposes a new approach for splitting
Uniffi
specific client types from the general Rust type. It introduces aUniffiWpLoginClient
wrapper type alongsideWpLoginClient
. There are a few advantages to this:WpLoginClient
andWpApiClient
. I'd like to renameWpRequestBuilder
toWpApiClient
, but I can't at the moment, because that name is also used in the Kotlin wrapper. However, with this approach, I can do that by separating the exported client asUniffiWpApiClient
.WpLoginClient
This new type currently only exposes one public function:
api_discovery
. Here is how that works:https
prefix if the string doesn't start withhttp
, and one withwp-admin.php
suffix if the string ends withwp-admin
orwp-admin/
. The attempts construction is naive and only deals with direct string manipulation.futures::future::join_all
.UrlDiscoverySuccess
which contains the api details as well as all other attempts. If all attempts failed, it'll return an error containing information about all the attempts.Url Discovery Attempt
Url discovery attempts are carried out using a simple state machine. There isn't too much benefit to this in terms of the implementation itself, however, the main goal of this approach is to be able to report detailed data about each attempt back to the consumer which will allow us to improve the url discovery process. The side benefit of this approach is its extensibility. It's very likely that we'll want to handle many more different cases and having a solid approach will give us a way to do that without making a spaghetti out of it.
Here is how it works:
ParsedUrl
, returning an error if it can't parse it.HEAD
request to it and parsing the headers to find "https://api.w.org/". If the request fails or if it can't find the header, it'll return an error.GET
request to the found api root (from Step 2) and parses it asWpApiDetails
. If the request fails or if it can't parse the response, it'll return an error.Kotlin Wrapper Changes
WpLoginClient
which allows us to keep theWpRequestExecutor
internal. It also simplifies the construction of this client, not needing a request executor to be passed to it.Unit & Integration Tests
Per usual, the PR adds a lot of new tests:
WpNetworkHeaderMap
from single and multi mapsTo Test
make test-server && make dump-mysql && make backup-wp-content-plugins
cargo test --test '*' -- --test-threads 1
cd native/kotlin && ./gradlew :api:kotlin:integrationTest