Skip to content

Commit

Permalink
Merge pull request #61 from aleixq/main
Browse files Browse the repository at this point in the history
Integrate files_sharing_webapppassword
  • Loading branch information
pbek authored Apr 19, 2023
2 parents ee37b4e + 591197b commit 3d3dccd
Show file tree
Hide file tree
Showing 11 changed files with 423 additions and 10 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,34 @@
[![Test](https://github.com/digital-blueprint/webapppassword/actions/workflows/test.yml/badge.svg)](https://github.com/digital-blueprint/webapppassword/actions/workflows/test.yml)

This is a Nextcloud app to generate a temporary app password and set CORS headers to allow
WebDAV/CalDAV access from inside a webpage.
WebDAV/CalDAV and Share API access from inside a webpage.

Place this app in **nextcloud/apps/** or install it from the [Nextcloud App Store](https://apps.nextcloud.com/apps/webapppassword).

## Configuration

You can configure the allowed origins on the settings page of the application.
You can configure the allowed origins for both wwebdav/caldav or files sharing api on the settings
page of the application.


![screenshot](screenshot.png)

Alternatively you can also add this setting to your `config/config.php`
(it will be used if the origins setting on the settings page are empty).

`'webapppassword.origins' => ['https://example.com'],` - array of allowed origins
`'webapppassword.origins' => ['https://example.com'],` - array of allowed webdav/caldav origins

The setting is both used for the origin of the CORS headers for the WebDAV/CalDAV requests and
for the referrer check whether we want to generate a temporary app password.

Also, you can configure in the same way the files sharing part.

`'webapppassword.files_sharing_origins' => ['https://example.com'],` - array of allowed files sharing api origins

Under the hood it exposes parts of the sharing api (CRUD and the preflight OPTIONS endpoint) in this url:
https://example.com/index.php/apps/webapppassword/api/v1/shares


## Docker

You can use this container for development and testing of the application.
Expand Down
44 changes: 44 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,49 @@
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#create_token', 'url' => '/create', 'verb' => 'POST'],
['name' => 'admin#update', 'url' => '/admin', 'verb' => 'PUT'],
/*
* OCS Share API
*/
[
'name' => 'ShareAPI#getShares',
'url' => '/api/v1/shares',
'verb' => 'GET',
],
[
'name' => 'ShareAPI#getInheritedShares',
'url' => '/api/v1/shares/inherited',
'verb' => 'GET',
],
[
'name' => 'ShareAPI#createShare',
'url' => '/api/v1/shares',
'verb' => 'POST',
],
[
'name' => 'ShareAPI#preflighted_cors',
'url' => '/api/v1/shares',
'verb' => 'OPTIONS',
],
[
'name' => 'ShareAPI#pendingShares',
'url' => '/api/v1/shares/pending',
'verb' => 'GET',
],
[
'name' => 'ShareAPI#getShare',
'url' => '/api/v1/shares/{id}',
'verb' => 'GET',
],
[
'name' => 'ShareAPI#updateShare',
'url' => '/api/v1/shares/{id}',
'verb' => 'PUT',
],
[
'name' => 'ShareAPI#deleteShare',
'url' => '/api/v1/shares/{id}',
'verb' => 'DELETE',
]

],
];
4 changes: 4 additions & 0 deletions css/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
#webapppassword-origins {
width: 100%;
}

#files-sharing-webapppassword-origins {
width: 100%;
}
2 changes: 2 additions & 0 deletions js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
document.querySelector("#webapppassword-store-origins").onclick = (e) => {
const data = {
origins: document.querySelector("#webapppassword-origins").value,
files_sharing_origins: document.querySelector("#files-sharing-webapppassword-origins").value,
};

const apiUrl = OC.generateUrl('/apps/webapppassword/admin');
Expand All @@ -19,6 +20,7 @@ document.querySelector("#webapppassword-store-origins").onclick = (e) => {
.then(response => response.json())
.then((data) => {
document.querySelector("#webapppassword-origins").value = data.origins;
document.querySelector("#files-sharing-webapppassword-origins").value = data.files_sharing_origins;
const successIndicator = document.querySelector("#webapppassword-saved-message");
successIndicator.classList.add('show');

Expand Down
45 changes: 45 additions & 0 deletions lib/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,49 @@ public function setOrigins($value)
$this->config->setAppValue('webapppassword', 'origins', $value);
$this->logger->info('Origins were updated!');
}

/**
* Serializes the allowed share api origins in a string.
*
* @return string
* List allowed share api origins separated by commas.
*
*/
public function getFilesSharingOrigins(): string
{
$origins = $this->config->getAppValue('webapppassword', 'files_sharing_origins');

if ($origins === '') {
$origins = implode(',', $this->config->getSystemValue('webapppassword.files_sharing_origins', []));
}

if ($origins === null) {
$origins = '';
}

return implode(',', array_map('trim', explode(',', $origins)));
}

/**
* Gets an array of the defined share api allowed origins
*
* @return array
* List of allowed share api origins.
*/
protected function getFilesSharingOriginList()
{
return explode(',', $this->getFilesSharingOrigins());
}

/**
* Sets the defined share api allowed origins
*
* @param string $value
* Comma separated List of allowed share api origins.
*/
public function setFilesSharingOrigins($value)
{
$this->config->setAppValue('webapppassword', 'files_sharing_origins', $value);
$this->logger->info('Files Sharing Origins were updated!');
}
}
80 changes: 80 additions & 0 deletions lib/Controller/AccessControl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
// SPDX-FileCopyrightText: Aleix Quintana Alsius <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OCA\WebAppPassword\Controller;

use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSNotFoundException;

trait AccessControl {
/**
* Checks the origin of a request and modifies response.
*
* @param DataResponse $response
* @return DataResponse
* @throws NotFoundException
* @throws OCSBadRequestException
* @throws OCSException
* @throws OCSForbiddenException
* @throws OCSNotFoundException
* @throws InvalidPathException
* @suppress PhanUndeclaredClassMethod
*/
protected function checkOrigin( DataResponse $response
): DataResponse {
$origins_allowed = $this->getOriginList();
if (in_array('access-control-allow-origin', $response->getHeaders())) {
throw new OCSNotFoundException($this->l->t('Could not create share'));
}

$origin = $this->request->getHeader('origin');
if (empty($origin) || !in_array($origin, $origins_allowed, true)) {
throw new OCSNotFoundException($this->l->t('Could not create share'));
}

$response->addHeader('access-control-allow-origin', $origin);
$response->addHeader('access-control-allow-methods', $this->request->getHeader('access-control-request-method'));
$response->addHeader('access-control-allow-headers', $this->request->getHeader('access-control-request-headers'));
$response->addHeader('access-control-expose-headers', 'etag, dav');
$response->addHeader('access-control-allow-credentials', 'true');
return $response;
}

/**
* Serializes the allowed origins in a string.
*
* @return string
* List allowed origins separated by commas.
*
*/
protected function getOrigins(): string
{
// TODO DI $this->config->getAppValue('files_sharing_origins', 'origins');
// __construct must be reimplemented as config prop in parent is private...
$config = \OC::$server->getConfig();
$origins = $config->getAppValue('webapppassword', 'files_sharing_origins');

if ($origins === '') {
$origins = implode(',', $config->getSystemValue('webapppassword.files_sharing_origins', []));
}

if ($origins === null) {
$origins = '';
}

return implode(',', array_map('trim', explode(',', $origins)));
}

/**
* Gets an array of the defined allowed origins
*
* @return array
* List of allowed origins.
*/
protected function getOriginList()
{
return explode(',', $this->getOrigins());
}
}
5 changes: 4 additions & 1 deletion lib/Controller/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ public function __construct(
* @return array with the updated values
*/
public function update(
$origins
$origins,
$files_sharing_origins
) {
$this->config->setOrigins($origins);
$this->config->setFilesSharingOrigins($files_sharing_origins);

return [
'origins' => $this->config->getOrigins(),
'files_sharing_origins' => $this->config->getFilesSharingOrigins(),
];
}
}
Loading

0 comments on commit 3d3dccd

Please sign in to comment.