/** * Blueprint constructor. * @param Database|null $db */ public function __construct(Database $db = null) { if (!$db) { $db = \Airship\get_database(); } $this->db = $db; }
/** * ContinuumLog constructor. * @param Database|null $db * @param string $component */ public function __construct(Database $db = null, string $component = 'continuum') { if (!$db) { $db = \Airship\get_database(); } $this->db = $db; $this->component = $component; }
/** * DBStore constructor. * @param DBInterface|null $db * @param string $table */ public function __construct(DBInterface $db = null, string $table = self::DEFAULT_TABLE) { $this->db = $db ?? \Airship\get_database(); if (empty($table)) { $table = self::DEFAULT_TABLE; } $this->table = $table; }
/** * Run a SQL file * * @param string $file * @param string $type * @return array * @throws \Airship\Alerts\Database\DBException */ public static function runSQLFile(string $file, string $type) : array { $db = \Airship\get_database(); if ($db->getDriver() !== $type) { // Wrong type. Abort! return []; } return $db->safeQuery(\file_get_contents($file)); }
/** * AirBrake constructor. * @param Database|null $db * @param array $config */ public function __construct(Database $db = null, array $config = []) { if (!$db) { $db = \Airship\get_database(); } if (empty($config)) { $state = State::instance(); $config = $state->universal['rate-limiting']; } $this->db = $db; $this->config = $config; }
/** * Make a generic slug for most tables * * @param string $title What are we basing the URL off of? * @param string $table Which table to check for duplicates? * @param string $column Which column to check for duplicates? * @return string */ protected function makeGenericSlug(string $title, string $table, string $column = 'slug') : string { if (IDE_HACKS) { $this->db = \Airship\get_database(); } $query = 'SELECT count(*) FROM ' . $this->db->escapeIdentifier($table) . ' WHERE ' . $this->db->escapeIdentifier($column) . ' = ?'; $slug = $base_slug = \Airship\slugFromTitle($title); $i = 1; while ($this->db->cell($query, $slug) > 0) { $slug = $base_slug . '-' . ++$i; } return $slug; }
/** * Keyggdrasil constructor. * * @param Hail|null $hail * @param DBInterface|null $db * @param array $channels */ public function __construct(Hail $hail = null, DBInterface $db = null, array $channels = []) { $config = State::instance(); if (empty($hail)) { $this->hail = $config->hail; } else { $this->hail = $hail; } if (empty($db)) { $db = \Airship\get_database(); } $this->db = $db; foreach ($channels as $ch => $config) { $this->channelCache[$ch] = new Channel($this, $ch, $config); } if (!self::$continuumLogger) { self::$continuumLogger = new Log($this->db, 'keyggdrasil'); } }
/** * @route / */ public function index() { if ($this->isLoggedIn()) { $this->storeLensVar('showmenu', true); $author_bp = $this->blueprint('Author'); $announce_bp = $this->blueprint('Announcements'); $blog_bp = $this->blueprint('Blog'); $page_bp = $this->blueprint('CustomPages'); if (IDE_HACKS) { $db = \Airship\get_database(); $author_bp = new Author($db); $announce_bp = new Announcements($db); $blog_bp = new Blog($db); $page_bp = new CustomPages($db); } $this->lens('index', ['announcements' => $announce_bp->getForUser($this->getActiveUserId()), 'stats' => ['num_authors' => $author_bp->numAuthors(), 'num_comments' => $blog_bp->numComments(true), 'num_pages' => $page_bp->numCustomPages(true), 'num_posts' => $blog_bp->numPosts(true)], 'title' => \__('Dashboard')]); } else { $this->storeLensVar('showmenu', false); $this->lens('login'); } }
<?php declare (strict_types=1); /** * This nukes the local Keyggdrasil cache. */ \ignore_user_abort(true); \set_time_limit(0); require_once \dirname(__DIR__) . '/bootstrap.php'; $db = \Airship\get_database(); $db->beginTransaction(); $db->exec("DROP TABLE airship_package_versions;"); $db->exec("DROP TABLE airship_package_cache;"); $db->exec("DROP TABLE airship_tree_updates;"); $db->exec("CREATE TABLE IF NOT EXISTS airship_tree_updates (\n treeupdateid BIGSERIAL PRIMARY KEY,\n channel TEXT,\n channelupdateid BIGINT,\n data TEXT,\n merkleroot TEXT,\n created TIMESTAMP DEFAULT NOW(),\n modified TIMESTAMP DEFAULT NOW()\n);"); $db->exec("CREATE INDEX ON airship_tree_updates (channel);"); $db->exec("CREATE INDEX ON airship_tree_updates (channelupdateid);"); $db->exec("CREATE UNIQUE INDEX ON airship_tree_updates (channel, channelupdateid);"); $db->exec("CREATE INDEX ON airship_tree_updates (merkleroot);"); $db->exec("DROP TRIGGER IF EXISTS update_airship_tree_updates_modtime ON airship_tree_updates;"); $db->exec("CREATE TRIGGER update_airship_tree_updates_modtime\n BEFORE UPDATE ON airship_tree_updates\n FOR EACH ROW EXECUTE PROCEDURE update_modtime();"); $db->exec("CREATE TABLE IF NOT EXISTS airship_package_cache (\n packageid BIGSERIAL PRIMARY KEY,\n packagetype type_airship_package,\n supplier TEXT,\n name TEXT,\n installed BOOLEAN DEFAULT FALSE,\n current_version TEXT,\n skyport_metadata JSONB,\n created TIMESTAMP DEFAULT NOW(),\n modified TIMESTAMP DEFAULT NOW()\n);"); $db->exec("CREATE INDEX ON airship_package_cache (packagetype);"); $db->exec("CREATE INDEX ON airship_package_cache (supplier);"); $db->exec("CREATE INDEX ON airship_package_cache (name);"); $db->exec("CREATE UNIQUE INDEX ON airship_package_cache(packagetype, supplier, name);"); $db->exec("CREATE TABLE IF NOT EXISTS airship_package_versions (\n versionid BIGSERIAL PRIMARY KEY,\n package BIGINT REFERENCES airship_package_cache(packageid),\n version TEXT,\n checksum TEXT,\n commithash TEXT,\n date_released TIMESTAMP,\n treeupdateid BIGINT REFERENCES airship_tree_updates(treeupdateid),\n created TIMESTAMP DEFAULT NOW(),\n modified TIMESTAMP DEFAULT NOW()\n);"); $db->exec("CREATE INDEX ON airship_package_versions (version);"); $db->exec("CREATE INDEX ON airship_package_versions (checksum);"); $db->exec("CREATE UNIQUE INDEX ON airship_package_versions (package, version);"); $db->exec("DROP TRIGGER IF EXISTS update_airship_package_versions_modtime ON airship_package_versions;");
/** * Fetch a query string from the stored queries file * * @param string $index Which index to replace * @param array $params Parameters to be replaced in the query string * @param string $cabin Which Cabin are we loading? * @param string $driver Which database driver? * @return string * @throws NotImplementedException */ function queryString(string $index, array $params = [], string $cabin = \CABIN_NAME, string $driver = '') : string { static $_cache = []; if (empty($driver)) { $db = \Airship\get_database(); $driver = $db->getDriver(); } $cacheKey = Util::hash($cabin . '/' . $driver, \Sodium\CRYPTO_GENERICHASH_BYTES_MIN); if (empty($_cache[$cacheKey])) { $driver = \preg_replace('/[^a-z]/', '', \strtolower($driver)); $path = !empty($cabin) ? ROOT . '/Cabin/' . $cabin . '/Queries/' . $driver . '.json' : ROOT . '/Engine/Queries/' . $driver . '.json'; $_cache[$cacheKey] = \Airship\loadJSON($path); } $split_key = \explode('.', $index); $v = $_cache[$cacheKey]; foreach ($split_key as $k) { if (!\array_key_exists($k, $v)) { throw new NotImplementedException(\trk('errors.database.query_not_found', $index)); } $v = $v[$k]; } if (\is_array($v)) { throw new NotImplementedException(\trk('errors.database.multiple_candidates', $index)); } $str = $v; foreach ($params as $token => $replacement) { $str = \str_replace('{{' . $token . '}}', $replacement, $str); } return $str; }
/** * Verifies that the Merkle root exists, matches this package and version, * and has the same checksum as the one we calculated. * * @param InstallFile $file * @return bool */ public function verifyMerkleRoot(InstallFile $file) : bool { $debugArgs = ['supplier' => $this->supplier->getName(), 'name' => $this->package]; $db = \Airship\get_database(); $merkle = $db->row('SELECT * FROM airship_tree_updates WHERE merkleroot = ?', $file->getMerkleRoot()); if (empty($merkle)) { $this->log('Merkle root not found in tree', LogLevel::DEBUG, $debugArgs); // Not found in Keyggdrasil return false; } $data = \Airship\parseJSON($merkle['data'], true); $instType = \strtolower($this->type); $keyggdrasilType = \strtolower($data['pkg_type']); if (!\hash_equals($instType, $keyggdrasilType)) { $this->log('Wrong package type', LogLevel::DEBUG, $debugArgs); // Wrong package type return false; } if (!\hash_equals($this->supplier->getName(), $data['supplier'])) { $this->log('Wrong supplier', LogLevel::DEBUG, $debugArgs); // Wrong supplier return false; } if (!\hash_equals($this->package, $data['name'])) { $this->log('Wrong package', LogLevel::DEBUG, $debugArgs); // Wrong package return false; } // Finally, we verify that the checksum matches the entry in our Merkle tree: return \hash_equals($file->getHash(), $data['checksum']); }
/** * Set the database of this authentication library to match this * * @param string $dbIndex * @return Authentication ($this) */ public function setDatabaseByKey(string $dbIndex = '') : self { $this->db = \Airship\get_database($dbIndex); return $this; }
/** * @route ajax/authors_save_photo */ public function saveAuthorsPhoto() { $auth_bp = $this->blueprint('Author'); if (IDE_HACKS) { $db = \Airship\get_database(); $auth_bp = new Author($db); } $authorId = (int) $_POST['author']; if (!$this->isSuperUser()) { $authors = $auth_bp->getAuthorIdsForUser($this->getActiveUserId()); if (!\in_array($authorId, $authors)) { \Airship\json_response(['status' => 'ERROR', 'message' => \__('You do not have permission to access this author\'s posts.')]); } } if (!\Airship\all_keys_exist(['cabin', 'context', 'author', 'filename'], $_POST)) { \Airship\json_response(['keys' => array_keys($_POST), 'status' => 'ERROR', 'message' => 'Insufficient parameters']); } $result = $auth_bp->savePhotoChoice($authorId, $_POST['context'], $_POST['cabin'], $_POST['filename']); if (!$result) { \Airship\json_response(['status' => 'ERROR', 'message' => 'Could not save photo choice.', 'photo' => null]); } \Airship\json_response(['status' => 'OK', 'message' => 'Saved!']); }
<?php declare (strict_types=1); use Airship\Engine\{Gears, Hail, Keyggdrasil, State}; /** * Keyggdrasil updater -- either throw this in a cronjob or let it get * triggered every time a page loads after enough time has elapsed * * @global State $state * @global Hail $hail */ \ignore_user_abort(true); \set_time_limit(0); require_once \dirname(__DIR__) . '/bootstrap.php'; if (\is_readable(ROOT . '/config/databases.json')) { /** * Initialize the channel updater service */ $channels = \Airship\loadJSON(ROOT . '/config/channels.json'); $database = \Airship\get_database(); $state->logger->info('Keyggdrasil started'); $keyUpdater = Gears::get('TreeUpdater', $hail, $database, $channels); if (IDE_HACKS) { $keyUpdater = new Keyggdrasil($hail, $database, $channels); } $keyUpdater->doUpdate(); $state->logger->info('Keyggdrasil concluded'); } else { // We can't update keys without a place to persist the changes }
/** * Get the user's public display name. * * @param int|null $userId * @return string * @throws \Airship\Alerts\Database\DBException */ function user_unique_id(int $userId = null) : string { if (empty($userId)) { $userId = \Airship\LensFunctions\userid(); } $db = \Airship\get_database(); return $db->cell('SELECT uniqueid FROM airship_users WHERE userid = ?', $userId); }
/** * Choose a database. We don't do anything fancy, but a Gear * might decide to do something different. * * @return Contract\DBInterface */ protected function airshipChooseDB() : DBInterface { return \Airship\get_database(); }
/** * Update the version string in airship_package_cache * * @param string $type * @param UpdateInfo $info * @return bool */ public function updateDBRecord(string $type, UpdateInfo $info) : bool { $db = \Airship\get_database(); $db->beginTransaction(); $db->update('airship_package_cache', ['current_version' => $info->getVersion()], ['packagetype' => $type, 'supplier' => $info->getSupplierName(), 'name' => $info->getPackageName()]); return $db->commit(); }
/** * If another session triggered a password reset, we should be logged out * as per the Bridge configuration. (This /is/ an optional feature.) * * @param int $userID * @param bool $logOut * @return bool */ public function verifySessionCanary(int $userID, bool $logOut = true) : bool { if (empty($_SESSION['session_canary'])) { return false; } $db = \Airship\get_database(); $canary = $db->cell('SELECT session_canary FROM airship_users WHERE userid = ?', $userID); if (empty($canary)) { $this->log('No session canary was registered with this user in the database.', LogLevel::DEBUG, ['database' => $canary, 'session' => $_SESSION['session_canary']]); $this->completeLogOut(); return false; } if (!\hash_equals($canary, $_SESSION['session_canary'])) { $this->log('User was logged out for having the wrong canary.', LogLevel::DEBUG, ['expected' => $canary, 'possessed' => $_SESSION['session_canary']]); if ($logOut) { $this->completeLogOut(); } return false; } return true; }