-
Notifications
You must be signed in to change notification settings - Fork 135
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
Reject acceptedPromise if converting method data fails #536
Conversation
index.html
Outdated
<li>If required by the specification that defines the | ||
<var>handler</var>, <a data-cite= | ||
"!WEBIDL#dfn-convert-ecmascript-to-idl-value">convert</a> | ||
<var>data</var> to an IDL value. Rethrow any exceptions. |
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.
You can't throw an exception from in parallel.
It seems unlikely we want to error if the user installs a payment handler which doesn't accept the provided data. Maybe if none of their installed handlers do... but that's already covered by the next step.
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.
You can't throw an exception from in parallel.
Ah yeah, will reject acceptPromise.
It seems unlikely we want to error if the user installs a payment handler which doesn't accept the provided data.
Sure... but...
Maybe if none of their installed handlers do... but that's already covered by the next step.
Ok, but something bad needs to happen with invalid data? I'm confused about where that should go.
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.
Sure, if the data is invalid for all payment apps, then the next step (which already exists) will fail. But we need to give every payment app a chance. If one succeeds, but 3 fail, it's not invalid data.
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.
Ok, got you. So we just ignore bad conversions as "unsupported". I guess as long as we notify the developer of bad conversions in the error console, that should be ok (or else it's gonna be hard to debug).
To be clear, trying to solve for: const methodData = [{
supportedMethods: ["basic-card", "https://foo.com/pay"],
data: { supportedTypes: ['THIS IS NOT A VALID ENUM VALUE!!'] }
}];
const request = new PaymentRequest(methodData, details, options);
try {
// When converting data, should `supportedTypes` cause `acceptPromise` to reject?
const response = await request.show();
} catch(err) {
} |
That is already rejected before this PR, since no payment handlers support that data, so the next step takes care of rejecting the promise. What this PR starts rejecting is: const methodData = [{
supportedMethods: ["basic-card", "bitcoin"],
data: { supportedTypes: "credit" }
}; because "bitcoin" doesn't support "credit". Is that intentional? It seems wrong to me; instead it makes more sense to me to do what the spec currently says, and display UI for paying with basic-card/credit, and ignore the bitcoin supported method. EDIT: switched from "visa" to "credit" (the latter is actually a valid supportedType for basic-card). |
this still feels super messed up to me. You could potentially end up with completely incompatible data types and property name clashes.
|
Yeah, definitely. I don't understand why supportedMethods is an array at all; it seems strange to think that the same In other words, given that we have supportedMethods being an array, the current spec seems better than requiring |
I can only assume this was done with the assumption that Ideally, you then want: const methodData = [{
supportedMethods: ["basic-card", "https://bank.com/basic-card"],
data: { supportedTypes: "visa" }
}, {
supportedMethods: ["crypto-currency", "https://bit.com/coin"],
data: { cryptoCurrencyThing: "thing" }
}]; So you don't mix types. If you mix data types, this is going to all come crashing down. |
@domenic, the more I think I about it, the more I think we should reject I can't think of any valid use case for mixing |
For those watching at home, the following would be all fine: const methodData = [{
// Must match "basic-card" spec, undergoes conversion
supportedMethods: ["https://bank.com/any-type", "basic-card"],
// .data MUST BE `BasicCardRequest`, because "basic-card" present.
data: { supportedTypes: ["visa"] }
}, {
// Must match "tokenized-thing" spec, undergoes conversion
supportedMethods: ["tokenized-thing", "https://bit.com/coin", "https://bank.com/any-type"],
data: { cryptoCurrencyThing: "thing" }
}, {
// .data treated as a normal object, no dictionary conversion.
supportedMethods: ["https://foo.com/bar", "https://bank.com/any-type"],
data: { foo: "bar", "thumb": "drive", anything: "goes" }
}]; But: const methodData = [
// This would cause a rejection, iff "future-card" is supported:
{
supportedMethods: ["https://foo.com/future-card", "future-card"],
data: { supportedTypes: ['THIS IS NOT A VALID VALUE!!'] }
},
// iff "future-card" is not supported, this one is still ok:
{
supportedMethods: ["https://foo.com/tokenized-thing", "tokenized-thing"],
data: { tokensAreFancy: true }
},
{
// This also throws
supportedMethods: ["basic-card", "nonbasic-card"],
data: { supportedTypes: "credit" }
}
] |
@marcoscaceres and @domenic this was discussed at some length on a WG call a few weeks ago and has been a niggling issue since pretty much the first payment method spec was written. My understanding from @rsolomakhin and @zkoch was that the data is treated as an opaque object and no validation is done against the IDL in the payment method spec. The browser passes the opaque data onto the payment handler which then parses it and uses it. If it is invalid then the response from the handler will indicate this. The Before you say: "But we need to look at the filters like In an ideal world each
The proposal to add a new member Another way to solve this is that we are revisiting the idea of handlers defining a function which is presented with the opaque |
On 25 May 2017, at 7:16 pm, Adrian Hope-Bailie ***@***.***> wrote:
@marcoscaceres and @domenic this was discussed at some length on a WG call a few weeks ago and has been a niggling issue since pretty much the first payment method spec was written.
My understanding from @rsolomakhin and @zkoch was that the data is treated as an opaque object and no validation is done against the IDL in the payment method spec.
This is not correct. Please see:
w3c/payment-method-basic-card#23
If we don't want IDL conversion, then why would we use WebIDL?
WebIDL is not a data-structure definition language: it's a system for type coercion and moving things between c++ and js. Thus, we can't say on one hand "oh! It's Web IDL..." but then "it's an opaque blob".
If we really don't want WebIDL, then we should not use it as the basis for BasicCardRequest.
The browser passes the opaque data onto the payment handler which then parses it and uses it. If it is invalid then the response from the handler will indicate this.
Again, this doesn't match what basic card spec says.
The basic-card payment method is "special" because the handler is internal to the browser but the implementation of how the data is validated shouldn't be exposed in the Payment Request spec.
I'm sorry, but again you are mistaken. It's not special and it's not treated as special. Anything can act as a "basic-card" handler (including proprietary payment methods denoted by a URL) if registered to handle that type.
Also, if it's expected to be a basicCardRequest, then it must be treated as WebIDL or we should stop using WebIDL to represent BasicCardRequest.
Before you say: "But we need to look at the filters like supportedTypes before the data is passed to the handler". I know.
I don't think this is where we were going.
In an ideal world each PaymentMethodData would have:
A set of identifiers it applies to
A blob of opaque data that the browser ignores and simply passes to the handler
This seems like a massive security risk. Passing arbitrary data to apps that are expecting well-structured payment requests seems extremely bad.
I don't think I would want to do that.
A set of filters used to filter handlers based on their capabilities
This doesn't match the spec.
The proposal to add a new member filters was rejected on the basis that Chrome have already deployed this and moving supportedTypes from data to filters is too disruptive.
Another way to solve this is that we are revisiting the idea of handlers defining a function which is presented with the opaque data and can respond true/false if they will be able to handle the payment.
No, we are fine to work with the current structure: we just need to define some simple rules to avoid the insanity of arbitrary .data types (at least, that's my opinion). That's why I'm proposing having .data be converted to the PMI's data type (when not null).
… —
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Neither of the two cases you state are the ones I am worried about. The one I am worried about is const methodData = [{
supportedMethods: ["basic-card", "nonbasic-card"],
data: { supportedTypes: "credit" }
}]; where nonbasic-card does not support the "credit" type (instead e.g. only "debit" or "giftcard"). I'd like the WG to discuss and pick one of the following:
If a position on this was previously documented please link me to it :). I don't otherwise feel comfortable changing this in an "editorial" PR. |
My position is 2.
I thought this was "editorial" because I thought we were just not clear in the behaviour - and because the PR from the other spec had not been merged. I didn't realize there would be disagreement on something that's clearly broken. |
I'm not willing to merge a normative change of this magnitude without confirmation from the WG, sorry. |
Let's put it on the 8 June agenda [1] |
Zach understands the problem, so I'm happy for him to represent my position on the call. Otherwise please move the call to a reasonable hour so I can participate.
… On 1 Jun 2017, at 10:41 pm, ianbjacobs ***@***.***> wrote:
Let's put it on the 8 June agenda [1]
Ian
[1] https://github.com/w3c/webpayments/wiki/Agenda-20170608
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I agree there is a lot of confusion here that is not really related to this issue. What I want is a simple working group decision on whether we're willing to change the semantics of my example from #536 (comment) from working to not working. More accurately, please see my "I'd like the WG to discuss and pick one of the following:" I don't think this requires the working group to figure out how bitcoin works with payment request, or gain a better understanding of Web IDL. This is a fairly narrowly-scoped question, setting aside the the attempts to several people in this thread to blow it up into a larger discussion. |
Agree (even if I'm guilty of the blow up). @domenic, please also make a choice. I'll delete any comments that are not choice related. |
In the future, let's not delete comments (you are welcome to delete your own, of course), but instead create a new issue and redirect over that way. |
Sure, will do. |
Hey there! Sorry, I'm late to the game. Our current implementation does not throw if you use non- |
Thanks @rsolomakhin I also said there it should throw 😭 And Microsoft didn't respond. In light of new information, we should really get the Edge folks to let us know what they are doing here too. @patrickkettner, I'm really struggling to get an Edge version to run Web Platform tests on (it doesn't want to install with virtual box, and I'm scared of bricking a work machine with a insider build). Could you please please please help us? We have access to Suace Labs - so maybe we can run against Edge 15 somehow? |
I believe @adrianba gave a 👍 on my "may throw" proposal, which is hard to notice. |
index.html
Outdated
<ol> | ||
<li>If required by the specification that defines the | ||
<var>handler</var>, <a data-cite= | ||
"!WEBIDL#dfn-convert-ecmascript-to-idl-value">convert</a> |
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 if we go with this architecture you need to JSON-parse before you convert, otherwise you're just converting it to an IDL DOMString, which is no good.
index.html
Outdated
<li>If required by the specification that defines the | ||
<var>handler</var>, <a data-cite= | ||
"!WEBIDL#dfn-convert-ecmascript-to-idl-value">convert</a> | ||
<var>data</var> to an IDL value. If it results in a error, |
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.
s/a/an
@marcoscaceres I may be misunderstanding what you have done here but I think you have replaced an algorithm for determining which handlers are suitable to process the payment request with an algorithm that validates the payment method specific data. We've all agreed that the latter is required but I think it should be in addition to the former not replace it. i.e. For all accepted methods in the request, validate the This does beg the question as to whether methods with invalid data should just be discarded with a warning? |
They could be. That's an implementation detail tho. Just interested in getting the |
Sure but this PR does discard some aspects of the original algorithm that are still required so I don't think it can be merged as is. |
index.html
Outdated
capabilities supplied by the payment handler match those provided | ||
by <var>data</var>, the payment handler matches. | ||
<li>Let <var>methods</var> be a list of <a>payment methods</a> | ||
that support <var>identifiers</var>. |
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 don't think "payment methods support identifiers". The identifiers identify the payment methods. The payment handlers support the payment methods.
I prefer the earlier text.
Ian
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 switch it back.
@adrianhopebailie, please provide code counter examples. If you can't show actual code examples then we can't have a discussion.
@marcoscaceres are you saying that if you delete something then in order to earn the privilege of engaging in a discussion with you on why, I must first re-write what you removed? |
Blocked on #551 |
Just a note that we discussed on 15 June at the WPWG call: @zkoch is going to help coordinate with @marcoscaceres a fix that addresses both topics this text intends to cover: looping through payment methods and validation. |
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.
LGTM. I think we've now addressed both use cases: validation of data AND finding matching payment handlers based on data and identifier
Thanks for adding back payment handler matching! |
c42f088
to
5896b12
Compare
"!WEBIDL#dfn-convert-ecmascript-to-idl-value">convert</a> to | ||
<a data-cite="!WEBIDL#idl-object">object</a>. | ||
</li> | ||
<li>If conversion results in an error, reject |
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.
Isn't the intent here to discard this tuple and continue (possibly logging an error in the process)?
i.e. Rejecting the promise and terminating the algorithm results in no matched payment handlers, even if there are multiple (identifer, data)
tuples and only one has invalid data.
Is it possible to throw and not reject the promise so that the browser can log the error and continue the next iteration of the loop?
If so, I propose the following, or something similar:
<li>If conversion results in an error, discard
the <var>paymentMethod</var> tuple, throw the error and process
the next tuple.</li>
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 does "discard" mean? That's not a well-defined operation, on tuples or anything 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.
I understand Adrian to be distinguishing two possible behaviors in the face of invalid data:
- Abandon that particular payment method identifier/data pair or
- Abandon the entire payment request
I favor the former behavior (and think AdrianHB does).
Ian
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.
OK. In that case I don't understand the suggestion. Discarding the tuple is a meaningless operation, and throwing the error is in direct contradiction to processing the next tuple (throwing an error terminates the algorithm, like it does in all programming languages).
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.
@domenic The algorithm is a loop through a list of tuples. I am proposing that instead of terminating the algorithm when bad data is found in one tuple, we just discard the offending tuple that contains the bad data and continue with the next.
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.
Again, I don't understand what "discard" means. Would your sentence mean the same thing if you said "we just continue with the next"? And what happened to "throw the error"?
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.
@domenic please, try and understand that the majority of this WG are not experts on browser internals. We're trying our best to contribute nonetheless. Have some patience and read the whole comment.
I only made a code suggestion because the last time I tried to contribute anything @marcoscaceres refused to read it unless it had code in it.
If you re-read my original comment I asked the following question:
Is it possible to throw and not reject the promise so that the browser can log the error and continue the next iteration of the loop?
If so, I propose...
I.e. There is a parsing step happening inside a loop. Can the parsing step throw and can the logic inside the loop catch and log the error and then continue?
This is the experience I'd expect a developer to get:
- They call the API with a list of 3 payment methods
- They have 3 different payment handlers registered that can each handle one of these payment methods
- One payment method has bad data
- They are presented with only 2 payment handlers to choose to handle the payment
- An error is logged to the browser console
I used the phrase "discard" because in the process of looping through this list of payment methods we are also establishing a list of payment handlers that match them. If a payment method has bad data then it is "discarded" from the set used for matching.
Sorry if that terminology is confusing, I hope you understand my intent now and can suggest a better text replacement?
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.
To close the loop on this (apologies for this post merge):
We discussed this on yesterday's editor call. While there is certainly merit in ignoring the offending payment method and its related data blob, we've been moving in the direction of explicitly throwing errors for the purpose of developer clarity across this spec. It seems best to follow suit here.
We realize there are other options (e.g. console logging a warning), but as this is core to how PR works, an explicit throw was voted as the best option by the editors.
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.
Per @adrianba 's comment below, I understand the editors to have decided to take a fail fast approach to this API, therefor a payment request with bad data in one of the provided payment methods will fail entirely rather than simply logging an error.
For consistency, I recommend that the payment method identifier is also validated as part of this algorithm. It should either be a recognised short-string identifier or a valid URL form identifier (per the validity rules in the PMI spec).
Also, I wonder if this sentence in the PMI spec should be revised:
"User agents MUST NOT enforce validity or well-formedness of standardized payment method identifiers. "
LGTM - we've been moving in the direction of increasingly helping developers find issues so rejecting seems correct. |
Will start on tests this week. |
Align with w3c/payment-method-basic-card#23
Preview | Diff