在Rails中生成VAPID公钥并将其传递给Javascript

为了使用带有VAPID的Push API,我需要一个applicationServerKey

 serviceWorkerRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: applicationServerKey // we've got it with getApplicationServerKey() defined below }); 

我用Ruby在服务器端生成它:

 ecdsa_private_key = OpenSSL::PKey::EC.new 'prime256v1' ecdsa_private_key.generate_key sender.vapid_private_key = ecdsa_private_key.to_pem ecdsa_public_key = OpenSSL::PKey::EC.new ecdsa_private_key ecdsa_public_key.private_key = nil sender.vapid_public_key = ecdsa_public_key.to_pem 

然后我必须下载它:

 getApplicationServerKey: function () { return new Promise(function (resolve, reject) { var request = new Request('https://example.com/application_server_key'); fetch(request).then(function (response) { response.text().then(function (base64) { resolve(_.base64ToArrayBuffer(base64)); }); }); }); }, base64ToArrayBuffer: function (base64) { var binary_string = window.atob(base64); var len = binary_string.length; var bytes = new Uint8Array(len); for (var i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } return bytes.buffer; } 

密钥从控制器返回为base64字符串:

 ecdsa_public_key = OpenSSL::PKey.read @sender.vapid_public_key base64 = Base64.encode64(ecdsa_public_key.public_key.to_bn.to_s(2)) render text: base64 

问题是当我调用pushManager.subscribe时Firefox会返回此错误:

 DOMException [InvalidAccessError: "Invalid raw ECDSA P-256 public key." code: 15 nsresult: 0x8053000f] 

任何帮助表示赞赏。

更新 :它让我发疯…我也尝试使用hex而不是base64编码/解码,但我得到了同样的错误。

来自Ruby:

 $ ecdsa_public_key.to_text => "Private-Key: (256 bit)\npub: \n 04:28:a9:89:be:8a:a8:f2:f1:bf:ed:04:d2:28:e9:\n 70:e9:b7:f3:8c:3c:f7:20:dc:95:30:1a:72:77:66:\n 09:0d:29:f6:6c:6c:c8:45:6e:da:ac:05:d6:ff:43:\n 9a:66:d0:c3:4c:bc:4a:0f:a3:ad:e8:23:33:22:40:\n 20:9e:de:14:56\n ASN1 OID: prime256v1\n NIST CURVE: P-256\n" $ ecdsa_public_key.public_key.to_bn.to_s 16 => "0428A989BE8AA8F2F1BFED04D228E970E9B7F38C3CF720DC95301A727766090D29F66C6CC8456EDAAC05D6FF439A66D0C34CBC4A0FA3ADE823332240209EDE1456" 

正如您所看到的那样,它是一个P-256密钥(我不知道它为什么说私钥而不是公钥,但是,正如您从生成它的代码中看到的那样,它是一个公钥)。

然后我用Javascript fetch下载hex字符串,这就是我得到的:

 0428A989BE8AA8F2F1BFED04D228E970E9B7F38C3CF720DC95301A727766090D29F66C6CC8456EDAAC05D6FF439A66D0C34CBC4A0FA3ADE823332240209EDE1456 Array [ "04", "28", "A9", "89", "BE", "8A", "A8", "F2", "F1", "BF", 55 more… ] Uint8Array [ 4, 40, 169, 137, 190, 138, 168, 242, 241, 191, 55 more… ] ArrayBuffer { byteLength: 65 } // I get it by calling .buffer on the Uint8Array DOMException [InvalidAccessError: "Invalid raw ECDSA P-256 public key." code: 15 nsresult: 0x8053000f] 

从我在控制台中打印的中间步骤中可以看到,正确处理了密钥。 但是我仍然得到那个错误……

更新2 :相同的代码在Chrome中成功运行:我设法使用VAPID发送通知。 这可能是一个Firefox错误。

我通过删除.buffer解决了。

现在我直接将Uint8Array传递给subscribe (而不是array.buffer ),它可以在Chrome和Firefox上运行。