Skip to content

Commit

Permalink
Merge pull request #11 from nextcloud/finish
Browse files Browse the repository at this point in the history
Finish up the app for the release
  • Loading branch information
nickvergessen committed Nov 18, 2016
2 parents 975fc29 + c503fba commit 7f8fae4
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 16 deletions.
24 changes: 24 additions & 0 deletions appinfo/certificate.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEEjCCAvoCAhAeMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
dXRob3JpdHkwHhcNMTYxMTE4MDk1OTU5WhcNMjcwMjI0MDk1OTU5WjAiMSAwHgYD
VQQDFBduZXh0Y2xvdWRfYW5ub3VuY2VtZW50czCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBANFPvX6AkI/EmwIU4z37bYxdXt4iIQSn3abXgZ7GXNSaEvfH
XIR4f/HIiee5vqdGC/cXFdCrJ93xEt84dqLzp58T1I4bsrizAANAmRvIZwvoCCUg
XNLhTJ9vLT3KY+CHKKWvB1I1GezcPeisOTz1cr6Avrek455yBn/+2rIr9NgxzDAQ
aazIw8dhYWo6dLU1dYmaUH+ECTTBdeggPvLtCPuYRtiX46DtSXuSPu5OsSlPNiLM
ViHZoDOoE89cGxzooV8BSzuVI6qRld19vJGLwg40ieTxpLXgpJxSaV3zZdHCdN8P
vmW2njIsG/9Mb0TuSQGrQtIify2nZNg7+kov3xKrDi2IjiePyYJ+e5i56WikPLDy
N6Mc+clNwLg5rqszkPRrTfoUoHUg4dVe5V/lHV3WH+pA92YbAWYhalB2Bl1jNHhA
S5LEoDbYUckXgc79Et+VxEsDjE1NBBk6q86tQh48Adr6DxqQzBpO7FQIRGHUma2/
Zv1z4QNSgkT/PdjWYhx9XChCq+oqEnYKL7iC9UP+J0+XZ8fnKMBU1W7w4t801cFV
XxJySBfgLYu4hUSu1CQEamva4H6PW3dYOHz5F7/u+nbw2b93zawE+87hqki3EX7+
kMUytxZn1VHwMoERn5R2D+exegUU0ag3iE9r0VTa+IAONpGGTsMKZB3ws6AJAgMB
AAEwDQYJKoZIhvcNAQELBQADggEBACGryCPDF0LmYQ2/pNq7mNEE+E8qFG8cJND7
2zYW7upEd1ohpCUBTyf0sSvcBqUBYwXh9fEkfh72XdnbPQUvuanDJkeMzEsXe2FX
2JCV7Kq+5cRIFHopqDTDYEb+FYRKLYcryE+MmTW4zQkDUY/LmIGQQ9Yc9qxvdTAB
TiSmckVtkDiTTThQG7ATqLoT2Oxartv7W3fnAFzg/VlLFTy8uOZiixwFe6Z/vdaF
A/Pscy9CqJHH4xml3Ag2LLvuPUtHiA6lDcezCSaMAQtk2yUAI9ykCbUEU5W5Nt4H
h05GGDaWvfE3CalylW2+nYaUCPN/kb1Mteegsj8AXheuy0oPyO4=
-----END CERTIFICATE-----
4 changes: 4 additions & 0 deletions img/app-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions img/app.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 98 additions & 14 deletions lib/Cron/Crawler.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
use OCP\IGroupManager;
use OCP\IUser;
use OCP\Notification\IManager as INotificationManager;
use phpseclib\File\X509;

class Crawler extends TimedJob {

const FEED_URL = 'https://nextcloud.com/blogfeed/';
const FEED_URL = 'https://pushfeed.nextcloud.com/feed';

/** @var string */
protected $appName;
Expand Down Expand Up @@ -65,38 +66,50 @@ public function __construct($appName, IConfig $config, IGroupManager $groupManag
$this->clientService = $clientService;

// Run once per day
$this->setInterval(1); // FIXME 24 * 60 * 60);
$this->setInterval(24 * 60 * 60);
}


protected function run($argument) {
$client = $this->clientService->newClient();
$response = $client->get(self::FEED_URL);

if ($response->getStatusCode() !== Http::STATUS_OK) {
try {
$feedBody = $this->loadFeed();
$rss = simplexml_load_string($feedBody);
if ($rss === false) {
throw new \Exception('Invalid XML feed');
}
} catch (\Exception $e) {
// Something is wrong 🙊
return;
}

$rss = simplexml_load_string($response->getBody());

/**
* TODO: https://github.com/contribook/main/issues/8
if ($rss->channel->pubDate === $this->config->getAppValue($this->appName, 'pub_date', '')) {
$lastPubDate = $this->config->getAppValue($this->appName, 'pub_date', 'now');
if ($lastPubDate === 'now') {
// First call, don't spam the user with old stuff...
$this->config->setAppValue($this->appName, 'pub_date', $rss->channel->pubDate);
return;
} else if ($rss->channel->pubDate === $lastPubDate) {
// Nothing new here...
return;
}
*/

$lastPubDateTime = new \DateTime($lastPubDate);

foreach ($rss->channel->item as $item) {
$id = md5((string) $item->guid);
if ($this->config->getAppValue($this->appName, $id, '') === 'published') {
continue;
}
$pubDate = new \DateTime((string) $item->pubDate);

if ($pubDate < $lastPubDateTime) {
continue;
}

$notification = $this->notificationManager->createNotification();
$notification->setApp($this->appName)
->setDateTime(new \DateTime((string) $item->pubDate))
->setDateTime($pubDate)
->setObject($this->appName, $id)
->setSubject(Notifier::SUBJECT, [(string) $item->author, (string) $item->title])
->setSubject(Notifier::SUBJECT, [(string) $item->title])
->setLink((string) $item->link);

foreach ($this->getUsersToNotify() as $uid) {
Expand All @@ -110,6 +123,77 @@ protected function run($argument) {
$this->config->setAppValue($this->appName, 'pub_date', $rss->channel->pubDate);
}

/**
* @return string
* @throws \Exception
*/
protected function loadFeed() {
$signature = $this->readFile('.signature');

if (!$signature) {
throw new \Exception('Invalid signature fetched from the server');
}

$certificate = new X509();
$certificate->loadCA(file_get_contents(\OC::$SERVERROOT . '/resources/codesigning/root.crt'));
$loadedCertificate = $certificate->loadX509(file_get_contents(__DIR__ . '/../../appinfo/certificate.crt'));

// Verify if the certificate has been revoked
$crl = new X509();
$crl->loadCA(file_get_contents(\OC::$SERVERROOT . '/resources/codesigning/root.crt'));
$crl->loadCRL(file_get_contents(\OC::$SERVERROOT . '/resources/codesigning/root.crl'));
if ($crl->validateSignature() !== true) {
throw new \Exception('Could not validate CRL signature');
}
$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
$revoked = $crl->getRevoked($csn);
if ($revoked !== false) {
throw new \Exception('Certificate has been revoked');
}

// Verify if the certificate has been issued by the Nextcloud Code Authority CA
if($certificate->validateSignature() !== true) {
throw new \Exception('App with id nextcloud_announcements has a certificate not issued by a trusted Code Signing Authority');
}

// Verify if the certificate is issued for the requested app id
$certInfo = openssl_x509_parse(file_get_contents(__DIR__ . '/../../resources/nextcloud_announcements.crt'));
if(!isset($certInfo['subject']['CN'])) {
throw new \Exception('App with id nextcloud_announcements has a cert with no CN');
}
if($certInfo['subject']['CN'] !== 'nextcloud_announcements') {
throw new \Exception(sprintf('App with id nextcloud_announcements has a cert issued to %s', $certInfo['subject']['CN']));
}

$feedBody = $this->readFile('.rss');

// Check if the signature actually matches the downloaded content
$certificate = openssl_get_publickey(file_get_contents(__DIR__ . '/../../resources/nextcloud_announcements.crt'));
$verified = (bool)openssl_verify($feedBody, base64_decode($signature), $certificate, OPENSSL_ALGO_SHA512);
openssl_free_key($certificate);

if (!$verified) {
// Signature does not match
throw new \Exception('Feed has an invalid signature');
}

return $feedBody;
}

/**
* @param string $file
* @return string
* @throws \Exception
*/
protected function readFile($file) {
$client = $this->clientService->newClient();
$response = $client->get(self::FEED_URL . $file);
if ($response->getStatusCode() !== Http::STATUS_OK) {
throw new \Exception('Could not load file');
}
return $response->getBody();
}

/**
* Get the list of users to notify
* @return string[]
Expand Down
16 changes: 14 additions & 2 deletions lib/Notification/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
namespace OCA\NextcloudAnnouncements\Notification;


use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
Expand All @@ -38,13 +39,18 @@ class Notifier implements INotifier {
/** @var IFactory */
protected $l10nFactory;

/** @var IURLGenerator */
protected $url;

/**
* @param string $appName
* @param IFactory $l10nFactory
* @param IURLGenerator $url
*/
public function __construct($appName, IFactory $l10nFactory) {
public function __construct($appName, IFactory $l10nFactory, IURLGenerator $url) {
$this->appName = $appName;
$this->l10nFactory = $l10nFactory;
$this->url = $url;
}

/**
Expand Down Expand Up @@ -72,7 +78,13 @@ public function prepare(INotification $notification, $languageCode) {
$parameters[0] = trim(substr($parameters[0], 0, $openingBracket));
}

$notification->setParsedSubject($l->t('%s announced “%s”', $parameters));
$notification->setParsedSubject($l->t('Nextcloud announcement'))
->setParsedMessage($parameters[1]);

if (method_exists($notification, 'setIcon')) {
$notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath($this->appName, 'app-dark.svg')));
}

return $notification;

default:
Expand Down

0 comments on commit 7f8fae4

Please sign in to comment.