-
Notifications
You must be signed in to change notification settings - Fork 18
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
[V3] Encode Pending Browser Switch Request as Base64 String #90
[V3] Encode Pending Browser Switch Request as Base64 String #90
Conversation
result.put("shouldNotify", shouldNotifyCancellation); | ||
if (metadata != null) { | ||
result.put("metadata", metadata); | ||
byte[] requestJSONBytes = requestJSON.toString().getBytes(StandardCharsets.UTF_8); |
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.
Base 64 encoding is technically optional, though it does make the state string appear to the merchant as an opaque data type to discourage tampering. Base64 encoding also has an added benefit of masking the data to prevent casual observation of browser switch metadata e.g. intercepting an ec-token over a screen share.
* | ||
* @param intent the intent to return to your application containing a deep link result from the | ||
* browser flow | ||
* @param pendingRequestState the {@link BrowserSwitchStartResult.Success} token returned from |
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 not sure about the state/token naming here, those don't align in my mind. Maybe startResultDetails
or startResultInfo
or storedStartResult
and remove token
from the description?
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 agree the naming can be improved. Choosing the right names for Browser Switch will maximize the Developer Experience and influence the DX in core.
For me the only thing with "details" and "info" that's conflicting is an implication that the string we return can provide information at runtime. Technically it's an opaque string that we don't want merchants to inspect.
We should definitely remove the word token, that's a holdover from what I called it originally. But in a way this "state" is similar to a BT nonce–we don't expect merchants to inspect the value for details because the structure of the data is undefined i.e. doesn't follow semantic versioning.
Could we maybe shorten it to requestState
? Or continue to ideate as a group this might be something to get some 👀's on. I'd be interested in seeing how this bubbles up to the features in the Core SDK too that could help us pick the right names.
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 think storedStartResult
makes sense. "result" seems generic enough for a merchant to not want to inspect its value.
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 like storedStartResult
for this method. The only thing where the naming doesn't scale as nicely is when the result is unpacked, we'd end up with result.storedStartResult
.
I'm wondering now if we should just go with something like originalRequest
to keep it simple? It'll still be opaque because the type is String
, and it would work nicely in both contexts (start()
and parse()
).
Also reiterating the main reason we make this value a String
is because strings work nicely with all Android persistence mechanisms e.g. SharedPrefs, DataStore, etc. We only need the merchant to hold on to this value for us to remove the responsibility of state restoration out of the SDK. We've gotten a good number of inbounds on that in the past, which makes us think that state restoration logic may be unique to each individual merchant app.
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.
What if we had separate naming for the start()
and parse()
steps? It might give a better description for each for both steps.
Start - startResultToStore
when (val result = browserSwitchClient.start(this, browserSwitchOptions)) {
is BrowserSwitchStartResult.Success ->
PendingRequestStore.put(this, result.startResultToStore)
...
}
Parse - storedStartResult
PendingRequestStore.get(this)?.let { storedStartRequest ->
when (val result = browserSwitchClient.parseResult(intent, storedStartResult)) {
...
}
}
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.
Honestly I still kind of think the pendingRequest
naming is a little more clear for what it is - a request that hasn't been completed yet. Maybe we could change the types to Started
and Failure
to better indicate that the request hasn't completed successfully yet?
when (val pendingRequest = browserSwitchClient.start(this, browserSwitchOptions)) {
is BrowserSwitchPendingRequest.Started ->
PendingRequestStore.put(this, pendingRequest.requestToStore)
...
}
Also maybe something like completeRequest
would make more sense than parse
to indicate what is required by the merchant?
PendingRequestStore.get(this)?.let { storedPendingRequest ->
when (val result = browserSwitchClient.completeRequest(intent, storedPendingRequest)) {
...
}
}
Can't decide what would be most clear for merchants. Tagging in @scannillo @jaxdesmarais @saperi22 for more opinions
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 like that suggestion. I think the consumer of Browser Switch could name the return value of browserSwitchClient.start(this, browserSwitchOptions)
anything they wanted. But I agree with pendingRequest
.
I also think completeRequest()
is more clear than parse()
.
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.
Agree on pendingRequest
and completeRequest
, those both sound like the most clear options for both us and merchants
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.
PR for renaming parseResult()
to completeRequest()
: #101
return new BrowserSwitchRequest(requestCode, Uri.parse(url), metadata, returnUrlScheme, shouldNotify); | ||
|
||
@NonNull | ||
static BrowserSwitchRequest fromBase64EncodedJSON(@NonNull String base64EncodedRequest) throws BrowserSwitchException { |
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 guess we should weigh the benefits of base64encoding compared to the extra merchant integration lift of having to handle the Failure
type for all browser based flows. I could go either way. What do others think?
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.
Oh yeah def. We can't really enforce JSON tampering though. We may still need the failure scenario for the case where we're unable to reconstruct the original BrowserSwitchRequest
.
* | ||
* @param intent the intent to return to your application containing a deep link result from the | ||
* browser flow | ||
* @param pendingRequestState the {@link BrowserSwitchStartResult.Success} token returned from |
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 think storedStartResult
makes sense. "result" seems generic enough for a merchant to not want to inspect its value.
// Links | ||
// Base64 Encode a String in Android: https://stackoverflow.com/a/7360440 | ||
|
||
// TODO: consider encryption | ||
// Ref: https://medium.com/fw-engineering/sharedpreferences-and-android-keystore-c4eac3373ac7 | ||
|
||
// TODO: Rename to `BrowserSwitchStartRequest` and remove `BrowserSwitchOptions` in favor this class |
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.
Should we remove these TODOs before merging the PR in?
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 agree, we may be able to convert these to JIRA tickets.
This PR might need to be closed and re-worked after all the changes in browser switch - @sshropshire can you revert the naming changes or open a new PR with just the base64 encoding work? |
Closing this after discussion with @sarahkoop. Will create a new PR with the Base64 encoding changes. |
Summary of changes
BrowserSwitchPendingRequest
toBrowserSwitchStartResult
ComponentActivity
forBrowserSwitchClient#start()
methodBrowserSwitchResult
toBrowserSwitchParseResult
BrowserSwitchInfo
helper classChecklist
Authors