RUN apt clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
-RUN npm install --unsafe-perm --global uglify-js less sass puppeteer favicons crx3 oslllo-svg-fixer terser nw-builder@^4
+RUN npm install --unsafe-perm --global uglify-js less sass puppeteer favicons crx3 oslllo-svg-fixer terser
RUN pip3 install font-line
RUN groupadd sudo;useradd -d /application -g 33 -G sudo -s /bin/bash -u 1001 toolbox
# PHP-FPM packages need a nudge to make them docker-friendly
COPY overrides.conf /etc/php/8.1/fpm/pool.d/z-overrides.conf
-#CMD ["/usr/sbin/php-fpm8.1", "-O" ]
COPY startup /usr/bin/startup
CMD exec /usr/bin/startup
--- /dev/null
+<?php
+
+namespace App\Console\Commands;
+
+use Cubist\Backpack\Console\Commands\CubistCommand;
+use Cubist\Util\Files\Files;
+use Cubist\Util\Zip;
+
+class UpdateNWJS extends CubistCommand
+{
+ /** @see https://nwjs.io/ */
+
+ protected $signature = 'updatenwjs';
+ protected const VERSION = '0.75.0';
+ protected const FFMPEG_VERSION = '0.73.0';
+
+ public function handle()
+ {
+ $this->_update('win', 'x64');
+ $this->_update('osx', 'x64');
+ }
+
+ protected function _update($platform, $arch = 'x64')
+ {
+ // Get NWJS
+ $path = Files::mkdir(resource_path('nwjs/' . $platform . '/' . $arch));
+ $tmp = Files::tempnam() . '.zip';
+ $tmpDir = Files::tmpdir();
+ copy('https://dl.nwjs.io/v' . self::VERSION . '/nwjs-v' . self::VERSION . '-' . $platform . '-' . $arch . '.zip', $tmp);
+ Zip::extract($tmp, $tmpDir);
+ if ($platform === 'osx') {
+ $todelete = ['credits.html'];
+ } else {
+ $todelete = ['credits.html'];
+ }
+ $nwjs = $tmpDir . '/nwjs-v' . self::VERSION . '-' . $platform . '-' . $arch;
+ foreach ($todelete as $item) {
+ `rm -rf $nwjs/$item`;
+ }
+ $mv = 'rsync -av --delete ' . $nwjs . '/ ' . Files::mkdir($path);
+ `$mv`;
+ unlink($tmp);
+
+ // Get FFMPEG
+ $destLib = Files::mkdir(resource_path('fluidbookpublication/packager/_ffmpeg'));
+ $tmp = Files::tempnam() . '.zip';
+ $tmpDir = Files::tmpdir();
+ copy('https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download/' . self::FFMPEG_VERSION . '/' . self::FFMPEG_VERSION . '-' . $platform . '-' . $arch . '.zip', $tmp);
+ Zip::extract($tmp, $tmpDir);
+ if ($platform === 'win') {
+ $src = 'ffmpeg.dll';
+ $dest = $platform . '-' . $arch . '.dll';
+ } else {
+ $src = $dest = 'libffmpeg.dylib';
+ }
+ copy($tmpDir . '/' . $src, $destLib . $dest);
+
+
+ }
+}
namespace App\Fluidbook\Packager;
+use CFPropertyList\CFPropertyList;
+use Cubist\Net\SSH2;
use Cubist\Util\CommandLine;
+use Cubist\Util\Files\Files;
+use Cubist\Util\Zip;
class MacOS extends WindowsZIP
{
protected $nwplatform = 'osx';
protected $arch = 'x64';
- protected $nwversion = '0.72.0';
- protected $node_platform = 'mac';
protected $exenameMaxlength = 28;
public $type = 'mac_exe_html';
protected $packageIconExt = 'icns';
public function makePackage($zip)
{
$this->preparePackage();
- $toDelete = ['chromedriver', 'credits.html', 'minidump_stackwalk', 'nwjc', 'payload', 'v8_context_snapshot.bin', 'natives_blob.bin', 'libffmpeg.dylib'];
- foreach ($toDelete as $item) {
- $p = $this->getFinalPackageDir() . '/' . $item;
- `rm -rf "$p"`;
- }
- if ($zip) {
- $res = $this->zip(null);
- } else {
- $res = $this->getFinalPackageDir();
- }
$this->postPackage();
- $this->setFinalURL(null);
- $this->setFinalPath($res);
- return $res;
+ return $this->getFinalPath();
}
public function getAppPath()
return parent::getFinalPackageDir();
}
+ protected function _nwbuilder4()
+ {
+ $base = Files::mkdir(resource_path('nwjs/' . $this->nwplatform . '/' . $this->arch));
+ $rsyncBase = "rsync -av --exclude nwjs.app/Contents/Resources/app.nw --delete $base $this->buildPath";
+ `$rsyncBase`;
+ $package = Files::mkdir($this->buildPath . '/nwjs.app/Contents/Resources/app.nw');
+ $rsyncFiles = "rsync -av --delete $this->vdir $package";
+ `$rsyncFiles`;
+ rename($this->buildPath . 'nwjs.app', $this->getAppPath());
+
+ $f = $this->getAppPath() . '/Contents/Info.plist';
+ file_put_contents($f, preg_replace('/\<string\>nwjs\<\/string\>/', '<string>' . htmlentities($this->exeName) . '</string>', file_get_contents($f), 1));
+ }
public function signExe()
{
- $this->signApp();
+
+ $appPath = $this->getAppPath();
+
+ //$ssh = new SSH2('paris.cubedesigners.com', 'vincent', 'atacama', 22022);
+ //$local_root = '/Users/vincent/Sign/';
+ $ssh = new SSH2('paris.cubedesigners.com', 'macossign', 'rntj55bw', 22622);
+ $local_root = '/Users/macossign/Documents/Sign/';
+
+ // Zip app
+ Zip::archive($appPath . '/..', $appPath . ".zip", 1);
+ $signScripts = resource_path('macossign');
+ // Copy zipped app and signing scripts to the remote mac server
+ $ssh->send($signScripts . '/toolbox/docodesign3', $local_root . 'docodesign3', 755);
+ $ssh->send($signScripts . '/toolbox/sign3', $local_root . 'sign3', 755);
+ $ssh->send($signScripts . '/toolbox/neededToRun3.entitlements', $local_root . 'neededToRun3.entitlements', 755);
+ $ssh->send($signScripts . '/workshop/docodesign', $local_root . 'docodesign', 755);
+ $ssh->send($signScripts . '/workshop/sign', $local_root . 'sign', 755);
+ $ssh->send($signScripts . '/workshop/neededToRun.entitlements', $local_root . 'neededToRun.entitlements', 755);
+ $ssh->send($appPath . ".zip", $local_root . $this->exeName . '.app.zip', 644);
+
+ // Sign app
+ $cl = new CommandLine($local_root . 'sign3');
+ $cl->setArg(null, $this->exeName);
+ $cl->execute($ssh);
+ $cl->debug();
+ $res = $cl->output;
+
+ $finalPath = $this->getPathBase('zip');
+ // Copy back signed
+ $ssh->recv($local_root . '/' . $this->exeName . '.app.zip', $finalPath);
+ $this->setFinalPath($finalPath);
+ $this->setFinalURL($this->getDownloadURL('zip'));
+
+ //`rm -rf $path`;
+ return $res;
}
public function setIcon()
copy($this->resource_path('_ffmpeg/libffmpeg.dylib'), $this->getAppPath() . '/Contents/Frameworks/nwjs Framework.framework/Versions/Current/libffmpeg.dylib');
}
- protected function signApp()
- {
- self::_signApp($this->getAppPath());
- }
-
- public static function _signApp($appPath, $back = true)
- {
- $local_root = '/Users/vincent/Sign/';
- $dist_root = '/mnt/sshfs/macparis' . $local_root;
- $f = 'tmp_' . md5(rand(0, 1000000)) . ".app";
- $path = $dist_root . $f;
-
- // Copy app to mac
- $cp = new CommandLine('cp');
- $cp->setArg('r');
- $cp->setArg(null, $appPath);
- $cp->setArg(null, $path);
- $cp->execute();
-
- // Sign app
- $cl = new CommandLine($local_root . 'sign');
- $cl->setSSH('paris.cubedesigners.com', 'vincent', 'atacama', 22022);
- $cl->setArg(null, $local_root . $f);
- $cl->execute();
- $res = $cl->output;
-
- if ($back) {
- // Copy back signed
- $cp = new CommandLine('rsync');
- $cp->setArg('r');
- $cp->setArg('l');
- $cp->setArg('p');
- $cp->setArg('D');
- $cp->setArg('v');
- $cp->setArg(null, $path . '/');
- $cp->setArg(null, $appPath . '/');
- $cp->execute();
- }
- //`rm -rf $path`;
- return $res;
- }
}
protected $buildPath;
protected $nwplatform = 'win';
protected $arch = 'x64';
- protected $nwversion = '0.72.0';
+ protected $nwversion = 'stable';
protected $appversion = '';
protected $node_platform = 'win';
protected $exenameMaxlength = 30;
protected $_compileOnConstruct = true;
protected $packageIconExt = 'ico';
- protected $nwbuildVersion = '4.0.8';
+ protected $nwbuildVersion = '4.2.0';
protected $nwCacheDir;
protected $_ext = 'html';
{
$this->buildPath = Files::mkdir($this->packager_path('/nwbuild/' . $this->type . '/' . $this->book_id));
$this->makeJSON();
- `umask 0000;sudo rm -rf $this->buildPath;mkdir -p 0777 $this->buildPath;chmod -R 777 $this->vdir;mkdir -p 0777 /application/tmp;chmod -R 777 /application/tmp`;
+ //`umask 0000;sudo rm -rf $this->buildPath;mkdir -p 0777 $this->buildPath;chmod -R 777 $this->vdir;mkdir -p 0777 /application/tmp;chmod -R 777 /application/tmp`;
$cl = $this->_nwbuilder4();
return file_exists($this->buildPath);
}
+
/**
* @return CommandLine
*/
protected function _nwbuilder4()
{
- $cl = new CommandLine('nwbuild');
- $cl->cd($this->vdir);
- $cl->setArg(null, 'package.json *');
- $cl->setArg('platform', $this->nwplatform);
- $cl->setArg('outDir', $this->buildPath);
- $cl->setArg('flavour', "normal");
- $cl->setArg('version', $this->nwversion);
- $cl->setArg('arch', $this->arch);
- $cl->execute();
- $cl->debug();
- return $cl;
+ $base = Files::mkdir(resource_path('nwjs/' . $this->nwplatform . '/' . $this->arch));
+ $rsyncBase = "rsync -av --exclude package.nw --delete $base $this->buildPath";
+ `$rsyncBase`;
+ $package = Files::mkdir($this->buildPath . '/package.nw');
+ $rsyncFiles = "rsync -av --delete $this->vdir $package";
+ `$rsyncFiles`;
+ rename($this->buildPath . 'nw.exe', $this->buildPath . $this->exeName . '.exe');
}
protected function getNWBuilder3Platform()
}
$cli = new CommandLine('C:/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64/signtool.exe');
- $cli->setManualArg("sign /f C:/Users/vince/Documents/Cubedesigners.cer /csp \"eToken Base Cryptographic Provider\" /k \"[SafeNet Token JC 0{{TYWjZacq%hAH98}}]=54C3F1B91759268A\" /tr http://timestamp.sectigo.com /td sha256 /fd sha256 /a $remote");
+ $cli->setManualArg("sign /f C:/Users/vince/OneDrive/Documents/Cubedesigners.cer /csp \"eToken Base Cryptographic Provider\" /k \"[SafeNet Token JC 0{{TYWjZacq%hAH98}}]=54C3F1B91759268A\" /tr http://timestamp.sectigo.com /td sha256 /fd sha256 /a $remote");
$cli->execute($ssh);
if (!stristr($cli->getOutput(), 'Successfully signed')) {
$ssh->unlink($remote);
'icon' => 'icon.png',
],
'app' => $app,
- 'nwbuild' => [
- 'platform' => $this->nwplatform,
- 'outDir' => $this->buildPath,
- 'cacheDir' => $this->nwCacheDir,
- 'flavour' => 'normal',
- 'version' => $this->nwversion,
- 'arch' => $this->arch,
- 'app' => $app,
- ],
'dependencies' =>
[
'child_process' => "^1.0.2",
foreach (['png', 'ico', 'icns'] as $format) {
$this->copy($this->theme->getFaviconPath($format), $this->vdir . '/icon.' . $format);
}
-
file_put_contents($this->vdir . '/package.json', json_encode($data));
}
--- /dev/null
+#!/usr/local/bin/node
+
+const APP = process.argv[2];
+const IDENTITY = process.argv[3];
+
+/****************************************************************************/
+
+console.log("### finding things to sign");
+
+const fs = require('fs');
+const child_process = require('child_process');
+
+const items = [];
+
+const frameworksDir = `${APP}/Contents/Frameworks/nwjs Framework.framework`;
+
+let currentVersionDir;
+for (const dir of fs.readdirSync(`${frameworksDir}/Versions`)) {
+ if (fs.statSync(`${frameworksDir}/Versions/${dir}`).isDirectory) {
+ currentVersionDir = `${frameworksDir}/Versions/${dir}`;
+ break;
+ }
+}
+if (!currentVersionDir) {
+ console.error(`couldn't find "${frameworksDir}/Versions/[version]"`);
+ process.exit(1);
+}
+for (const file of fs.readdirSync(`${currentVersionDir}`)) {
+ if (file.endsWith('.dylib')) {
+ items.push(`${currentVersionDir}/${file}`);
+ }
+}
+for (const file of fs.readdirSync(`${currentVersionDir}/Helpers`)) {
+ if (/^[a-z0-9_]*$/.test(file) || file.endsWith('.app')) {
+ items.push(`${currentVersionDir}/Helpers/${file}`);
+ }
+}
+
+for (const file of fs.readdirSync(`${currentVersionDir}/Libraries`)) {
+ if (file.endsWith('.dylib')) {
+ items.push(`${currentVersionDir}/Libraries/${file}`);
+ }
+}
+
+for (const file of fs.readdirSync(`${APP}/Contents/Library/LaunchServices`)) {
+ items.push(`${APP}/Contents/Library/LaunchServices/${file}`);
+}
+
+//for (const file of fs.readdirSync(`${currentVersionDir}/XPCServices`)) {
+// if (file.endsWith('.xpc')) {
+// items.push(`${currentVersionDir}/XPCServices/${file}`);
+// }
+//
+items.push(frameworksDir);
+
+/****************************************************************************/
+
+console.log("");
+console.log("### signing");
+
+function exec(cmd) {
+ console.log(cmd);
+ const result = child_process.spawnSync(cmd, {shell: true, stdio: 'inherit'});
+ if (result.status !== 0) {
+ console.log(`Command failed with status ${result.status}`);
+ if (result.error) console.log(result.error);
+ process.exit(1);
+ }
+}
+
+for (const item of items) {
+ exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements ./neededToRun3.entitlements "${item}"`);
+}
+
+exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements ./neededToRun3.entitlements "${APP}"`);
+
+/****************************************************************************/
+
+console.log("");
+console.log("### verifying signature");
+
+exec(`codesign --verify -vvvv "${APP}"`);
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+ <key>com.apple.security.automation.apple-events</key>
+ <true/>
+ <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+ <true/>
+ <key>com.apple.security.cs.allow-jit</key>
+ <true/>
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+ <true/>
+ <key>com.apple.security.cs.disable-executable-page-protection</key>
+ <true/>
+ <key>com.apple.security.cs.disable-library-validation</key>
+ <true/>
+ </dict>
+</plist>
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+cd /Users/macossign/Documents/Sign
+printf "Unlock keychain\n----\n\n"
+security unlock-keychain -p "rntj55bw" /Users/macossign/Library/Keychains/Apple.keychain-db
+printf "Unzip app file\n----\n\n"
+rm -rf "$1.app"
+unzip "$1.app.zip"
+rm -f "$1.app.zip"
+printf "Sign the app\n----\n\n"
+./docodesign3 "$1.app" "Developer ID Application: Cubedesigners (82TNE4UQ7A)"
+printf "Zip the app in order to be notarized\n----\n\n"
+ditto -c -k --sequesterRsrc --keepParent "$1.app" "$1.app.zip"
+printf "Notarize app and wait for confirmation\n----\n\n"
+xcrun notarytool submit --wait --apple-id "contact@cubedesigners.com" --team-id "82TNE4UQ7A" --password "tqwj-saik-dtdl-yrpc" "$1.app.zip"
+printf "Staple the app\n----\n\n"
+xcrun stapler staple "$1.app"
+printf "Rezip the app\n----\n\n"
+rm -f "$1.app.zip"
+ditto -c -k --sequesterRsrc --keepParent "$1.app" "$1.app.zip"
+printf "Remove the app (keep only zip)\n----\n\n"
+rm -rf "$1.app"
+chmod 777 "$1.app.zip"
--- /dev/null
+#!/usr/bin/env node
+
+const APP = process.argv[2];
+const IDENTITY = process.argv[3];
+
+/****************************************************************************/
+
+console.log("### finding things to sign");
+
+const fs = require('fs');
+const child_process = require('child_process');
+
+const items = [];
+
+const frameworksDir = `${APP}/Contents/Frameworks/nwjs Framework.framework`;
+
+let currentVersionDir;
+for (const dir of fs.readdirSync(`${frameworksDir}/Versions`)) {
+ if (fs.statSync(`${frameworksDir}/Versions/${dir}`).isDirectory) {
+ currentVersionDir = `${frameworksDir}/Versions/${dir}`;
+ break;
+ }
+}
+if (!currentVersionDir) {
+ console.error(`couldn't find "${frameworksDir}/Versions/[version]"`);
+ process.exit(1);
+}
+for (const file of fs.readdirSync(`${currentVersionDir}`)) {
+ if (file.endsWith('.dylib')) {
+ items.push(`${currentVersionDir}/${file}`);
+ }
+}
+for (const file of fs.readdirSync(`${currentVersionDir}/Helpers`)) {
+ if (/^[a-z0-9_]*$/.test(file) || file.endsWith('.app')) {
+ items.push(`${currentVersionDir}/Helpers/${file}`);
+ }
+}
+for (const file of fs.readdirSync(`${currentVersionDir}/Libraries`)) {
+ if (file.endsWith('.dylib')) {
+ items.push(`${currentVersionDir}/Libraries/${file}`);
+ }
+}
+for (const file of fs.readdirSync(`${currentVersionDir}/XPCServices`)) {
+ if (file.endsWith('.xpc')) {
+ items.push(`${currentVersionDir}/XPCServices/${file}`);
+ }
+}
+items.push(frameworksDir);
+
+/****************************************************************************/
+
+console.log("");
+console.log("### signing");
+
+function exec(cmd) {
+ console.log(cmd);
+ const result = child_process.spawnSync(cmd, {shell: true, stdio: 'inherit'});
+ if (result.status !== 0) {
+ console.log(`Command failed with status ${result.status}`);
+ if (result.error) console.log(result.error);
+ process.exit(1);
+ }
+}
+
+for (const item of items) {
+ exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements neededToRun.entitlements "${item}"`);
+}
+
+exec(`codesign --verbose --force --deep --strict --options runtime --timestamp --sign "${IDENTITY}" --entitlements neededToRun.entitlements "${APP}"`);
+
+/****************************************************************************/
+
+console.log("");
+console.log("### verifying signature");
+
+exec(`codesign --verify -vvvv "${APP}"`);
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+ <key>com.apple.security.automation.apple-events</key>
+ <true/>
+ <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+ <true/>
+ <key>com.apple.security.cs.allow-jit</key>
+ <true/>
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+ <true/>
+ <key>com.apple.security.cs.disable-executable-page-protection</key>
+ <true/>
+ <key>com.apple.security.cs.disable-library-validation</key>
+ <true/>
+ </dict>
+</plist>
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+printf "Unlock keychain\n----\n\n"
+security unlock-keychain -p "atacama" /Users/macossign/Library/Keychains/Apple.keychain-db
+/Users/vincent/Sign/docodesign "$1" "Developer ID Application: Cubedesigners (82TNE4UQ7A)"
+ditto -c -k --sequesterRsrc --keepParent "$1" "$1.zip"
+#xcode-select -s $1
+xcrun notarytool submit --wait --apple-id "contact@cubedesigners.com" --team-id "82TNE4UQ7A" --password "tqwj-saik-dtdl-yrpc" "$1.zip"
+xcrun stapler staple $1