Skip to content
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

Make the function signature overloads of SubtleCrypto#exportKey more flexible #1593

Merged
merged 11 commits into from
Jul 13, 2023
Merged

Conversation

steveluscher
Copy link
Contributor

@steveluscher steveluscher commented Jul 12, 2023

Problem

This test case fails with the current state of the exportKey overloads (playground).

(['jwk', 'raw', 'pkcs8', 'spki'] as KeyFormat[]).forEach(format => {
    crypto.subtle.exportKey(
      format, // ERROR
      {} as CryptoKey,
    );
});

Change

This PR makes it so that the "jwk" overload works as expected by producing Promise<JsonWebKey> as the return type, and the remaining keys in the KeyFormat union produce Promise<ArrayBuffer> as the return type, and the example code above typechecks correctly (playground).

…e flexible

# Problem

This test case _fails_ with the current state of the `exportKey` overloads ([playground](https://www.typescriptlang.org/play?#code/NocgVg7g1iA0AEIBOBDCdEAcoGMDOAHBiHtgJYgC6AdAGYD2SAoijgBYAUDSAtigC7wAvAD54AbwBQ8GfBxIAnpn71qeAK4AjfgBsAptT0APTI34BpPQq6M+-BOIC+8FHngBhRcvqWFASgBuaVkAehDZCMiAPQB+SUdAoA)).

```ts
['jwk', 'raw', 'pkcs8', 'spki'].forEach(format => {
    crypto.subtle.exportKey(
      format, // ERROR
      {} as CryptoKey,
    );
});
```

# Change

This PR makes it so that the `"jwk"` overload works as expected by producing `Promise<JsonWebKey>` as the return type, and the remaining keys in the `KeyFormat` union produce `Promise<ArrayBuffer>` as the return type, _and_ the example code above typechecks correctly.
@github-actions
Copy link
Contributor

Thanks for the PR!

This section of the codebase is owned by @saschanaz - if they write a comment saying "LGTM" then it will be merged.

@steveluscher
Copy link
Contributor Author

@microsoft-github-policy-service agree

@steveluscher steveluscher changed the title Make the function signature overloads of SubtleCrypto#exportKey more flexible Make the function signature overloads of SubtleCrypto#exportKey and SubtleCrypto#importKey more flexible Jul 12, 2023
@steveluscher
Copy link
Contributor Author

Mmm… hold on. I see why this doesn't work for importKey quite the same way. I'll revert that.

@steveluscher steveluscher changed the title Make the function signature overloads of SubtleCrypto#exportKey and SubtleCrypto#importKey more flexible Make the function signature overloads of SubtleCrypto#exportKeymore flexible Jul 12, 2023
@steveluscher steveluscher changed the title Make the function signature overloads of SubtleCrypto#exportKeymore flexible Make the function signature overloads of SubtleCrypto#exportKey more flexible Jul 12, 2023
@saschanaz
Copy link
Contributor

I'm pretty sure this is done to fix the jwk incorrectly returning ArrayBuffer. Can you write some unit tests and check the return type?

@steveluscher
Copy link
Contributor Author

Check out the second playground link; "jwk" still returns Promise<JsonWebKey>!

@saschanaz
Copy link
Contributor

saschanaz commented Jul 12, 2023

I mean: playground

function assertType<T>(_x: T) {}

const mockKey = {} as CryptoKey;
assertType<Promise<JsonWebKey>>(crypto.subtle.exportKey('jwk', mockKey));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also check what happens if the input is 'jwk' | 'pkcs8'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100%. I'm on it.

@saschanaz
Copy link
Contributor

I think we are blocked by microsoft/TypeScript#14107 which is still open.

@steveluscher
Copy link
Contributor Author

There we go! Updated the playground link in the description.

@saschanaz
Copy link
Contributor

Ah, that works better 👍

function assertType<T>(_x: T) {}

const mockKey = {} as CryptoKey;
assertType<Promise<ArrayBuffer | JsonWebKey>>(crypto.subtle.exportKey('' as KeyFormat, mockKey));
Copy link
Contributor

@saschanaz saschanaz Jul 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too loose as either Promise<ArrayBuffer> or Promise<JsonWebKey> will match the type. But not sure how to make it strict enough 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can test whether it works for both as Promise<ArrayBuffer> and as Promise<JsonWebKey>, like:

crypto.subtle.exportKey('' as KeyFormat, mockKey) as Promise<ArrayBuffer>; // type includes ArrayBuffer
crypto.subtle.exportKey('' as KeyFormat, mockKey) as Promise<JsonWebKey>; // type also includes JsonWebKey

Copy link
Contributor Author

@steveluscher steveluscher Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too loose as either Promise or Promise will match the type

Isn't that exactly the point when format is not known to yield one or the other?

How about this?

assertType<Promise<ArrayBuffer | JsonWebKey>>(
  crypto.subtle
    .exportKey("" as KeyFormat, mockKey)
    .then((ambiguousExportedKeyData) =>
      ambiguousExportedKeyData instanceof ArrayBuffer
        ? (ambiguousExportedKeyData satisfies ArrayBuffer)
        : (ambiguousExportedKeyData satisfies JsonWebKey)
    )
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that exactly the point when format is not known to yield one or the other?

Yes but that'll never fail when the return type regresses to either ArrayBuffer or JsonWebKey.

How about this?

Sounds good!

@saschanaz
Copy link
Contributor

This is technically a breaking change but I think it's reasonable.

LGTM

@github-actions github-actions bot merged commit 13115c8 into microsoft:main Jul 13, 2023
@github-actions
Copy link
Contributor

Merging because @saschanaz is a code-owner of all the changes - thanks!

@steveluscher steveluscher deleted the patch-1 branch July 13, 2023 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants