Я потрепал свои волосы в течение недели, пытаясь заставить push-уведомления Safari работать на MacOS.Я выполнил шаги, перечисленные здесь: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/NotificationProgrammingGuideForWebsites/PushNotifications/PushNotifications.html#//apple_ref/doc/uid/TP40013225-CH3-SW24 и здесь: https://medium.com/@rossbulat/safari-push-notifications-complete-setup-ef57f19bbb89, реализовал конечную точку для обслуживания zip-пакета и конечную точку ведения журнала, но я получаю сообщение об ошибке «Проверка подписи push-пакета не удалась».
Я использую nodejs для создания zip-пакета и подписания файла манифеста.
Код для этого:
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const child_process = require('child_process');
const rimraf = require('rimraf');
const archiver = require('archiver');
const websiteName = 'mywebsite.com';
const websiteFolder = 'mywebsite.com';
const websitePushID = 'web.com.mywebsite';
const allowedDomains = [
'https://www.mywebsite.nl',
'https://www.mywebsite.com'
];
const webServiceURL = 'https://api.mywebsite.com';
const urlFormatString = 'https://www.mywebsite.com/%@';
const authenticationToken = '3F2UyWU8VfJ6EHGZqd5TMteQ';
const certP12 = '../cert/certificate.p12';
const wwdrca = '../cert/AppleWWDRCA.pem';
const certPasswd = 'my password'; //p12 password
const raw_files = [
'website.json',
'icon.iconset/icon_16x16.png',
'icon.iconset/icon_16x16@2x.png',
'icon.iconset/icon_32x32.png',
'icon.iconset/icon_32x32@2x.png',
'icon.iconset/icon_128x128.png',
'icon.iconset/icon_128x128@2x.png'
];
const website = {
websiteName,
websitePushID,
allowedDomains,
urlFormatString,
authenticationToken,
webServiceURL
};
const manifest = {};
const createZip = () => {
return new Promise((resolve, reject) => {
const basePath = `${__dirname}/${websiteFolder}.pushpackage`;
console.log('website.json', `${basePath}/website.json`);
fs.writeFileSync(`${basePath}/website.json`, JSON.stringify(website));
console.log('manifest.json');
raw_files.forEach(file => {
const sha512 = crypto.createHash('sha512');
sha512.update(fs.readFileSync(`${basePath}/${file}`), 'binary');
manifest[file] = {
hashType: 'sha512',
hashValue: sha512.digest('hex')
};
});
fs.writeFileSync(`${basePath}/manifest.json`, JSON.stringify(manifest));
child_process.execSync(`openssl pkcs12 -in ${path.join(__dirname, certP12)} -nocerts -out private.pem -passin pass:${certPasswd} -passout pass:${certPasswd}`);
child_process.execSync(`openssl pkcs12 -in ${path.join(__dirname, certP12)} -clcerts -nokeys -out cert.pem -passin pass:${certPasswd}`);
child_process.execSync(`openssl smime -binary -sign -certfile ${path.join(__dirname, wwdrca)} -signer ${path.join(__dirname, '../cert', 'certificate.pem')} -inkey private.pem -in ${basePath}/manifest.json -out ${basePath}/signature -outform DER -passin pass:${certPasswd}`);
raw_files.push('manifest.json');
raw_files.push('signature');
if(fs.existsSync(`${basePath}.zip`)) {
fs.unlinkSync(`${basePath}.zip`);
}
const archive = archiver('zip');
const output = fs.createWriteStream(`${basePath}.zip`);
archive.pipe(output);
console.log('building Package');
raw_files.forEach(file => archive.append(fs.createReadStream(`${basePath}/${file}`), {name: file}));
archive.on('finish', () => {
console.log('finished');
return resolve();
});
console.log('finalize');
archive.finalize((err, bytes) => {
if(err) {
throw err;
}
console.log(`${bytes} total bytes`);
fs.unlink('cert.pem');
fs.unlink('private.pem');
rimraf.sync(basePath);
});
});
};
module.exports = createZip;
Поскольку проверка подписи не проходит, проблемадолжно быть в этой строке:
child_process.execSync(`openssl smime -binary -sign -certfile ${path.join(__dirname, wwdrca)} -signer ${path.join(__dirname, '../cert', 'certificate.pem')} -inkey private.pem -in ${basePath}/manifest.json -out ${basePath}/signature -outform DER -passin pass:${certPasswd}`);
Для аргумента -signer
я впервые использовал cert.pem
, сгенерированный в предыдущей строке:
child_process.execSync(`openssl pkcs12 -in ${path.join(__dirname, certP12)} -clcerts -nokeys -out cert.pem -passin pass:${certPasswd}`);
Но я думаю, что это необходимобыть файлом certificate.pem
, который я сгенерировал из файла certificate.p12
с помощью этой команды:
openssl pkcs12 -in certificate.p12 -out certificate.pem -nodes
Однако это не решает проблему.Я несколько раз следовал инструкциям, чтобы получить правильные сертификаты, и я почти уверен, что сделал это правильно, но я далеко не эксперт по сертификатам, так что, возможно, я что-то там не так сделал.Возможно, кто-то может проверить приведенный выше код, чтобы увидеть, является ли он правильным.
Любая помощь очень ценится, поскольку у моей головы едва хватает волос, чтобы вырвать ... спасибо!