index.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. const rsaPublicKeyPem = require('../rsa-public-key-pem')
  2. const {
  3. jwtVerify
  4. } = require('../../../npm/index')
  5. let authKeysCache = null
  6. module.exports = class Auth {
  7. constructor (options) {
  8. this.options = Object.assign({
  9. baseUrl: 'https://appleid.apple.com',
  10. timeout: 10000
  11. }, options)
  12. }
  13. async _fetch (url, options) {
  14. const { baseUrl } = this.options
  15. return uniCloud.httpclient.request(baseUrl + url, options)
  16. }
  17. async verifyIdentityToken (identityToken) {
  18. // 解密出kid,拿取key
  19. const jwtHeader = identityToken.split('.')[0]
  20. const { kid } = JSON.parse(Buffer.from(jwtHeader, 'base64').toString())
  21. let authKeys
  22. if (authKeysCache) {
  23. authKeys = authKeysCache
  24. } else {
  25. authKeys = await this.getAuthKeys()
  26. authKeysCache = authKeys
  27. }
  28. const usedKey = authKeys.find(item => item.kid === kid)
  29. /**
  30. * identityToken 格式
  31. *
  32. * {
  33. * iss: 'https://appleid.apple.com',
  34. * aud: 'io.dcloud.hellouniapp',
  35. * exp: 1610626724,
  36. * iat: 1610540324,
  37. * sub: '000628.30119d332d9b45a3be4a297f9391fd5c.0403',
  38. * c_hash: 'oFfgewoG36cJX00KUbj45A',
  39. * email: 'x2awmap99s@privaterelay.appleid.com',
  40. * email_verified: 'true',
  41. * is_private_email: 'true',
  42. * auth_time: 1610540324,
  43. * nonce_supported: true
  44. * }
  45. */
  46. const payload = jwtVerify(
  47. identityToken,
  48. rsaPublicKeyPem(usedKey.n, usedKey.e),
  49. {
  50. algorithms: usedKey.alg
  51. }
  52. )
  53. if (payload.iss !== 'https://appleid.apple.com' || payload.aud !== this.options.bundleId) {
  54. throw new Error('Invalid identity token')
  55. }
  56. return {
  57. openid: payload.sub,
  58. email: payload.email,
  59. emailVerified: payload.email_verified === 'true',
  60. isPrivateEmail: payload.is_private_email === 'true'
  61. }
  62. }
  63. async getAuthKeys () {
  64. const { status, data } = await this._fetch('/auth/keys', {
  65. method: 'GET',
  66. dataType: 'json',
  67. timeout: this.options.timeout
  68. })
  69. if (status !== 200) throw new Error('request https://appleid.apple.com/auth/keys fail')
  70. return data.keys
  71. }
  72. }