container = $container; } public function createIndexV1Array() { /** @var EntityManager $em */ $em = $this->container->get(EntityManager::class); $apps = $em ->getRepository(App::class) ->findBy([ 'status' => App::STATUS_APPROVED ]); $appObjects = []; $packageObjects = []; foreach ($apps as $app) { /** @var $app App */ $appObjects[] = [ "authorEmail" => "example@example.com", "authorName" => "example", "authorWebSite" => "https://example.org", "categories" => [ 'example' ], "suggestedVersionCode" => $app->getReleases()->first()->getVersionCode(), "name" => $app->getLabel(), "added" => 0, "packageName" => $app->getName(), "lastUpdated" => 0, "license" => "no" ]; $packages = []; foreach ($app->getReleases() as $release) { $packages[] = [ "added" => 0, "apkName" => "/apk/" . $app->getName() . "/" . $release->getVersionCode() . ".apk", "hash" => hash('sha256', $release->getApk()), "hashType" => "sha256", "minSdkVersion" => 4, "packageName" => $app->getName(), "sig" => "deadbeef", "signer" => "deadbeef", "size" => filesize($release->getApk()), "targetSdkVersion" => 28, "versionCode" => $release->getVersionCode(), "versionName" => $release->getVersionName() ]; } $packageObjects[$app->getName()] = $packages; } return [ 'repo' => [ 'timestamp' => time() * 1000, 'version' => 21, 'maxage' => 14, 'name' => $this->container->get('app.name'), 'description' => $this->container->get('app.description'), 'address' => "https://" . $this->container->get('app.domain') . '/repo' ], 'requests' => [ 'install' => [], 'uninstall' => [], ], "apps" => $appObjects, "packages" => $packageObjects ]; } public function createSigned($file, $contents) { $zip = new ZipArchive(); $zipPath = tempnam(sys_get_temp_dir(), 'zip'); $zip->open($zipPath, ZipArchive::CREATE); $fileDigest = sha1($contents, true); $fileHeader = 'Name: ' . $file . "\n"; $fileHeader .= 'SHA1-Digest: ' . base64_encode($fileDigest) . "\n\n"; $fileHeaderDigest = sha1($fileHeader, true); $manifest = "Manifest-Version: 1.0\n"; $manifest .= "Created-By: CubiStore\n\n"; $manifestHeaderDigest = sha1($manifest, true); $manifest .= $fileHeader; $manifestDigest = sha1($manifest, true); $fileManifest = "Signature-Version: 1.0\n"; $fileManifest .= "SHA1-Digest-Manifest-Main-Attributes: " . base64_encode($manifestHeaderDigest) . "\n"; $fileManifest .= "SHA1-Digest-Manifest: " . base64_encode($manifestDigest) . "\n"; $fileManifest .= "Created-By: CubiStore\n\n"; $fileManifest .= "Name: " . $file . "\n"; $fileManifest .= "SHA1-Digest: " . base64_encode($fileHeaderDigest) . "\n\n"; $zip->addFromString('META-INF/MANIFEST.MF', $manifest); $zip->addFromString('META-INF/1.SF', $fileManifest); $in = tempnam(sys_get_temp_dir(), 'repo'); file_put_contents($in, $fileManifest); $out = tempnam(sys_get_temp_dir(), 'repo'); $success = openssl_pkcs7_sign( $in, $out, 'file://' . __DIR__ . '/../../certs/cert.pem', 'file://' . __DIR__ . '/../../certs/key.pem', [], PKCS7_BINARY | PKCS7_NOATTR ); if (!$success) { $error = ''; while ($line = openssl_error_string()) { $error .= $line . "\n"; } throw new \RuntimeException($error); } unlink($in); $signed = file_get_contents($out); unlink($out); $contentOffset = strpos($signed, "\n\n"); $content = substr($signed, $contentOffset); $base64 = str_replace("\n", "", $content); $zip->addFromString('META-INF/1.RSA', base64_decode($base64)); $zip->addFromString($file, $contents); $zip->close(); $zipContent = file_get_contents($zipPath); unlink($zipPath); return $zipContent; } }