webpki
webpki copied to clipboard
Support anyPolicy Certificate Policy
I'm dealing with a certificate that has critical Certificate Policy (2.5.29.32) with anyPolicy policy. It would be appreciated if rustls-webpki supported this scenario. Also created an issue in https://github.com/briansmith/webpki/issues/268.
NSS supports Certificate Policies with anyPolicy.
An additional con is that if they're passing a non-iterable right now it's almost certainly a bug, but this would mask it.
For example: Promise.all(getA(), getB(), getC()) is a likely bug where they forgot to wrap it in [ ], which currently throws - with this overload, it would just return an empty object because the a promise has no properties.
iow, this feels like a nonstarter to me.
Yeah, this is begging for trouble.
MM also suggested the same issue, should we reopen?
@erights' suggestion was a bit different: basically saying "if the first arg is not iterable and arguments.length > 1, throw", and then the fallback would be to accept the lone non-iterable object argument and return an object.
Generally I like be strict on argument length, and it seems solve the misuse problem in this specific issue.
Not just Promise.all but all four, overloaded exactly this way.
I favor that it operates on exactly the enumerable own properties, whether string-named or symbol-named, like ... and assign do.
Nice uniformity across the two overloads because, for a normal array, all the numeric indexed properties are also enumerable own.
Not just Promise.all but all four, overloaded exactly this way.
This is definitely the way to go when it comes to designing a nice API that is going to be a joy to use.
We already have a bunch of ugly names in JavaScript, and we even have a precedent for trying to fix them, like Object.prototype.hasOwnProperty being replaced by Object.hasOwn now. We don't need more ugly names.
The method should always take a single argument so that when someone forgets [ and] they get a runtime error and realize the mistake.
An additional con is that if they're passing a non-iterable right now it's almost certainly a bug, but this would mask it.
For example:
Promise.all(getA(), getB(), getC())is a likely bug where they forgot to wrap it in[ ], which currently throws - with this overload, it would just return an empty object because theapromise has no properties.iow, this feels like a nonstarter to me.
Pretty much every developer now a day uses some IDE. Given that the IDE will complain that the function got too many arguments.
I would say that in the modern day, this complaint is no longer valid.
I don't use an IDE, and neither does every developer. The complaint will forever be valid.
I don't use an IDE, and neither does every developer.
That's why there is Pretty much every and not every... What do you use, then? (I am curious)
The complaint will forever be valid.
Both complaints will be forever valid. The point of this discussion is to determine if the benefit of putting an object to this function would ease more people than it would hurt.
Pros:
- A separate name for awaiting
ArrayandObjectcould confuse new users.Promise.all(...)andPromise.ownProperties(...)(orPromise.fromEntries(Object.entries(...))) is not something a new user not understandingown propertiescould easily deduce.Promise.all(...)should take all
Cons:
- Users might put an object with defined
Symbol.iterator, possibly throwing off the expected result- If using IDE, the result would be correctly deduced from the iterable type, thought caught, if not...
- For some, this might even be a desired "side" effect
- If decided that the number of arguments should not throw
- People with IDE should once again be saved it
- The others, I would assume they are knowledgeable enough to know what happened
I don't think a separate name is confusing to anyone; arguably, IDE autocomplete means it would be less confusing - that said, if we decide on a way to safely overload the existing mechanism, that's nice.
Personally I very much like the idea of overloading the existing methods.
As mentioned there is the risk of Symbol.iterator being added or removed from an object which is also being passed to the overloaded Promise.all and this changing the outcome at a distance. I think this risk level is low because:
- the primary use case for this overload is passing in an object literal, so the Symbol would need to be added to
Object.prototypeto go from the dictionary overload to the current iterable semantics. - The check for
arguments.length === 1reduces the risk when...arris used unintentionally, omitting the case where the iterable has a length of one. - There are already other APIs which have fallback semantics if the associated
Symbolprotocol is not present, such asArray.fromortoString.
One hypothetical way to further reduce the risk would be to only accept iterables or objects with a prototype set to null. However I think the complexity, boilerplate, and restrictiveness of adding this limitation is not justified for the estimated level of risk.
It would be great to get as much feedback from developers with a diverse range of backgrounds on how their would find the overload vs separate dedicated APIs.
Technically you could create an object with an iterator like so:
const obj = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
},
};
await Promise.all(obj) // [1, 2, 3]
If a user does this, it is done by design... The risk, therefore, arising from this is minimal. However, this (or any similar) example should be documented in the proposal.
May I suggest a poll? (vote for both if you please) 🚀: overload 🎉: separate dedicated APIs
After a few weeks, my passion for opposing this has cooled a bit. I care more about a workable solution than how that solution is implemented.
That said, I'm thinking also about type definitions from TypeScript, which gives me another concern. The current type definitions in TypeScript for Promise.all are:
// from es2015.iterable.d.ts
all<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>;
// from es2015.promise.d.ts
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;
https://github.com/microsoft/TypeScript/blob/main/src/lib/es2015.iterable.d.ts https://github.com/microsoft/TypeScript/blob/main/src/lib/es2015.promise.d.ts
What would the types look like when overloaded?
@ajvincent Presumably an extra overload along the lines of
all<T extends { [key: string]: unknown }>(obj: T): Promise<{ [P in keyof T]: Awaited<T[P]> }>
?
Since the array has -readonly I would assume this one would too. But yeah this overload is simple and correct.
if overloading, we would be overloading all of the Promise concurrency methods, right?
Both Promise.all and Promise.allSettled, I'd expect.
ah right, this wouldn't make much sense for any and race
There could be an overload for them...
const result = await Promise.race({
a: new Promise(() => {}), // never resolves - always loses the race
b: Promise.resolve(42),
});
result; // { b: 42 }
"a" in result; // false
"b" in result; // true
However I agree that I don't think we should pursue this design because Promise.race does not currently return an array container type so this overload would make a more significant change to the return type by adding a container that isn't there when an iterable is passed as an argument.
Promise.all and Promise.allSttled should return the container as resolved from the Symbol.Iterator or enumerable keys of given object (in this order).
Promise.race and Promise.any should accept iterable and object but return just the result of the promise.
We must be consistent with the current API.
We must be consistent with the current API.
The consistency here is that the overload is available when the method returns a container.
To pass an object to Promise.{race, any} could still be done as Promise.{race, any}(Object.values(obj)).
To pass an object to
Promise.{race, any}could still be done asPromise.race(Object.values(obj)).
True the benefit added by overload of Promise.{race, any} is minimal. Let's not mess with more than is necessary.