예제 #1
0
 /**
  * Post a new announcement
  *
  * @param array $post POST data from the Landing
  * @return bool
  */
 public function createAnnouncement(array $post) : bool
 {
     $this->db->beginTransaction();
     // We want a unique ID (collision chance 50% at 2^132)
     $query = 'SELECT count(*) FROM bridge_announcements WHERE uniqueid = ?';
     do {
         $unique = \Airship\uniqueId(33);
     } while ($this->db->exists($query, $unique));
     $this->db->insert('bridge_announcements', ['uniqueid' => $unique, 'title' => $post['title'] ?? '', 'contents' => $post['contents'] ?? '', 'format' => $post['format'] ?? 'HTML', 'only_admins' => !empty($post['only_admins'])]);
     return $this->db->commit();
 }
예제 #2
0
파일: Blog.php 프로젝트: paragonie/airship
 /**
  * Update a blog post
  *
  * @param array $post
  * @param array $old
  * @param bool $publish
  * @return bool
  */
 public function updatePost(array $post, array $old, bool $publish = false) : bool
 {
     $this->db->beginTransaction();
     $postUpdates = [];
     // First, update the hull_blog_posts entry
     if (!empty($post['author'])) {
         if ($post['author'] !== $old['author']) {
             $postUpdates['author'] = (int) $post['author'];
         }
     }
     if ($post['description'] !== $old['description']) {
         $postUpdates['description'] = (string) $post['description'];
     }
     if ($post['format'] !== $old['format']) {
         $postUpdates['format'] = (string) $post['format'];
     }
     if ($post['slug'] !== $old['slug']) {
         $bm = (string) $old['blogmonth'] < 10 ? '0' . $old['blogmonth'] : $old['blogmonth'];
         $exists = $this->db->cell('SELECT count(*) FROM view_hull_blog_list WHERE blogmonth = ? AND blogyear = ? AND slug = ?', $old['blogyear'], $bm, $post['slug']);
         if ($exists > 0) {
             // Slug collision
             return false;
         }
         $postUpdates['slug'] = (string) $post['slug'];
         if (!empty($post['redirect_slug'])) {
             $oldUrl = \implode('/', ['blog', $old['blogyear'], $bm, $old['slug']]);
             $newUrl = \implode('/', ['blog', $old['blogyear'], $bm, $post['slug']]);
             $this->db->insert('airship_custom_redirect', ['oldpath' => $oldUrl, 'newpath' => $newUrl, 'cabin' => $this->cabin, 'same_cabin' => true]);
         }
     }
     $now = new \DateTime();
     if (!empty($post['published'])) {
         try {
             $now = new \DateTime($post['published']);
         } catch (\Throwable $ex) {
         }
     }
     if (!\array_key_exists('category', $post)) {
         $post['category'] = 0;
     }
     if ($post['category'] !== $old['category']) {
         $postUpdates['category'] = (int) $post['category'];
     }
     if ($publish) {
         $postUpdates['status'] = true;
         $postUpdates['cache'] = !empty($post['cache']);
         // Let's set the publishing time.
         $postUpdates['published'] = $now->format(\AIRSHIP_DATE_FORMAT);
     }
     if ($post['title'] !== $old['title']) {
         $postUpdates['title'] = (string) $post['title'];
     }
     if (!empty($postUpdates)) {
         $this->db->update('hull_blog_posts', $postUpdates, ['postid' => $old['postid']]);
     }
     do {
         $unique = \Airship\uniqueId();
         $exists = $this->db->exists('SELECT COUNT(*) FROM hull_blog_post_versions WHERE uniqueid = ?', $unique);
     } while ($exists);
     // Second, create a new entry in hull_blog_post_versions
     $this->db->insert('hull_blog_post_versions', ['post' => $old['postid'], 'body' => $post['blog_post_body'], 'format' => $post['format'], 'live' => $publish, 'metadata' => \json_encode($post['metadata'] ?? []), 'published_by' => $publish ? $this->getActiveUserId() : null, 'uniqueid' => $unique]);
     if (empty($old['tags'])) {
         $old['tags'] = [];
     }
     if (empty($post['tags'])) {
         $post['tags'] = [];
     }
     // Now let's update the tag relationships
     $tag_ins = \array_diff($post['tags'], $old['tags']);
     $tag_del = \array_diff($old['tags'], $post['tags']);
     foreach ($tag_del as $del) {
         $this->db->delete('hull_blog_post_tags', ['postid' => $old['postid'], 'tagid' => $del]);
     }
     foreach ($tag_ins as $ins) {
         $this->db->insert('hull_blog_post_tags', ['postid' => $old['postid'], 'tagid' => $ins]);
     }
     if ($publish) {
         \Airship\clear_cache();
     }
     return $this->db->commit();
 }
예제 #3
0
 /**
  * ConfigFilter constructor.
  *
  * Specifies the filter rules for the cabin configuration POST rules.
  */
 public function __construct()
 {
     $this->addFilter('config_extra.blog.cachelists', new BoolFilter())->addFilter('config_extra.blog.comments.depth_max', new IntFilter())->addFilter('config_extra.blog.comments.enabled', new BoolFilter())->addFilter('config_extra.blog.comments.guests', new BoolFilter())->addFilter('config_extra.blog.comments.recaptcha', new BoolFilter())->addFilter('config_extra.blog.per_page', new IntFilter())->addFilter('config_extra.file.cache', new IntFilter())->addFilter('config_extra.homepage.blog-posts', (new IntFilter())->setDefault(5))->addFilter('config_extra.cache-secret', (new StringFilter())->setDefault(\Airship\uniqueId(33)))->addFilter('config_extra.recaptcha.secret-key', new StringFilter())->addFilter('config_extra.recaptcha.site-key', new StringFilter())->addFilter('twig_vars.active-motif', new StringFilter())->addFilter('twig_vars.title', new StringFilter())->addFilter('twig_vars.tagline', new StringFilter())->addFilter('twig_vars.blog.title', new StringFilter())->addFilter('twig_vars.blog.tagline', new StringFilter());
 }
예제 #4
0
 /**
  * Get a unique ID (and make sure it doesn't exist)
  *
  * @param string $table
  * @param string $column
  * @return string
  */
 protected function uniqueId(string $table, string $column = 'uniqueid') : string
 {
     do {
         $unique = \Airship\uniqueId();
     } while ($this->db->exists('SELECT count(*) FROM ' . $this->db->escapeIdentifier($table) . ' WHERE ' . $this->db->escapeIdentifier($column) . ' = ?', $unique));
     return $unique;
 }
예제 #5
0
<?php

declare (strict_types=1);
/**
 * This script runs when upgrading to v1.4.0 from an earlier version.
 * It adds the uniqueid column to the hull_blog_post_versions table then
 * retcons a uniqueid for each existing blog post version.
 */
$db = \Airship\get_database();
$db->exec('ALTER TABLE hull_blog_post_versions ADD uniqueid TEXT;');
foreach ($db->run('SELECT * FROM hull_blog_post_versions') as $ver) {
    // Get a unique ID:
    do {
        $unique = \Airship\uniqueId();
        $exists = $db->exists('SELECT count(*) FROM hull_blog_post_versions WHERE uniqueid = ?', $unique);
    } while ($exists);
    // Now assign it.
    $db->update('hull_blog_post_versions', ['uniqueid' => $unique], ['versionid' => $ver['versionid']]);
}
// Finally...
$db->exec('CREATE UNIQUE INDEX ON hull_blog_post_versions(uniqueid);');
예제 #6
0
 /**
  * @covers \Airship\uniqueId()
  */
 public function testUniqueId()
 {
     $strings = [];
     for ($i = 0; $i < 1024; ++$i) {
         $strings[] = \Airship\uniqueId(33);
     }
     $this->assertSame($strings, \array_unique($strings), 'Collision!');
     for ($i = 18; $i < 30; ++$i) {
         $unique = \trim(\Airship\uniqueId($i), '=');
         $this->assertSame($i, Binary::safeStrlen($unique));
     }
 }
예제 #7
0
<?php

declare (strict_types=1);
require_once \dirname(__DIR__) . '/src/bootstrap.php';
/**
 * This gives each user a uniqueid if they do not already have one.
 *
 * It *should* be safe to remove, but we're holding off on doing that
 * until version 2.0.0.
 */
$db = \Airship\get_database();
foreach ($db->run('SELECT * FROM airship_users WHERE uniqueid IS NULL OR LENGTH(uniqueid) < 24') as $r) {
    $db->update('airship_users', ['uniqueid' => \Airship\uniqueId()], ['userid' => $r['userid']]);
    echo "{$r['userid']}\n";
}
예제 #8
0
파일: email.php 프로젝트: paragonie/airship
                 if ($state->universal['email']['smtp']['connection_class'] !== 'smtp') {
                     $transportConfig['connection_config'] = ['username' => $state->universal['email']['smtp']['username'], 'password' => $state->universal['email']['smtp']['password']];
                 }
                 if (!empty($state->universal['email']['smtp']['disable_tls'])) {
                     $transportConfig['connection_config']['port'] = !empty($state->universal['email']['smtp']['port']) ? $state->universal['email']['smtp']['port'] : 25;
                 } else {
                     $transportConfig['connection_config']['ssl'] = 'tls';
                     $transportConfig['port'] = !empty($state->universal['email']['smtp']['port']) ? $state->universal['email']['smtp']['port'] : 587;
                 }
                 $transport->setOptions(new \Zend\Mail\Transport\SmtpOptions($transportConfig));
                 break;
             case 'File':
                 $transport = new Zend\Mail\Transport\File();
                 /** @noinspection PhpUnusedParameterInspection */
                 $transport->setOptions(new \Zend\Mail\Transport\FileOptions(['path' => !empty($state->universal['email']['file']['path']) ? $state->universal['email']['file']['path'] : ROOT . '/files/email', 'callback' => function (Zend\Mail\Transport\File $t) : string {
                     return \implode('_', ['Message', \date('YmdHis'), \Airship\uniqueId(12) . '.txt']);
                 }]));
                 break;
             case 'Sendmail':
                 if (!empty($state->universal['email']['sendmail']['parameters'])) {
                     $transport = new Zend\Mail\Transport\Sendmail($state->universal['email']['sendmail']['parameters']);
                 } else {
                     $transport = new Zend\Mail\Transport\Sendmail();
                 }
                 break;
             default:
                 throw new Exception(\trk('errors.email.invalid_transport', \print_r($state->universal['email']['transport'], true)));
         }
     }
     $state->mailer = $transport;
 }
예제 #9
0
 /**
  * Generate a unique random public ID for this user, which is distinct from the username they use to log in.
  *
  * @return string
  */
 protected function generateUniqueId() : string
 {
     $unique = '';
     $query = 'SELECT count(*) FROM airship_users WHERE uniqueid = ?';
     do {
         if (!empty($unique)) {
             // This will probably never be executed. It will be a nice easter egg if it ever does.
             $state = State::instance();
             $state->logger->log(LogLevel::ALERT, "A unique user ID collision occurred. This should never happen. (There are 2^192 possible values," . "which has approximately a 50% chance of a single collision occurring after 2^96 users," . "and the database can only hold 2^64). This means you're either extremely lucky or your CSPRNG " . "is broken. We hope it's luck. Airship is clever enough to try again and not fail " . "(so don't worry), but we wanted to make sure you were aware.", ['colliding_random_id' => $unique]);
         }
         $unique = \Airship\uniqueId();
     } while ($this->db->exists($query, $unique));
     return $unique;
 }
예제 #10
0
 /**
  * Create the default pages (about, contact).
  */
 protected function finalDefaultPages()
 {
     foreach (\Airship\list_all_files(ROOT . '/Installer/default_pages') as $file) {
         $filedata = \file_get_contents($file);
         if (\preg_match('#/([^./]+).md$#', $file, $m)) {
             $pageid = $this->db->insertGet('airship_custom_page', ['cabin' => 'Hull', 'url' => $m[1], 'active' => true, 'cache' => false], 'pageid');
             $this->db->insert('airship_custom_page_version', ['page' => $pageid, 'uniqueid' => \Airship\uniqueId(), 'published' => true, 'formatting' => 'Markdown', 'bridge_user' => 1, 'body' => $filedata, 'metadata' => '[]', 'raw' => false]);
         }
     }
 }