1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
<?php
/**
* ownCloud - Richdocuments App
*
* @author Ashod Nakashian
* @copyright 2016 Ashod Nakashian ashod.nakashian@collabora.co.uk
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
namespace OCA\Richdocuments\Db;
use \OCA\Richdocuments\Download;
use \OCA\Richdocuments\DownloadResponse;
/**
* @method string generateFileToken()
* @method string getPathForToken()
*/
class Wopi extends \OCA\Richdocuments\Db{
const DB_TABLE = '`*PREFIX*richdocuments_wopi`';
// Tokens expire after this many seconds (not defined by WOPI specs).
const TOKEN_LIFETIME_SECONDS = 1800;
protected $tableName = '`*PREFIX*richdocuments_wopi`';
protected $insertStatement = 'INSERT INTO `*PREFIX*richdocuments_wopi` (`owner_uid`, `editor_uid`, `fileid`, `path`, `token`, `expiry`)
VALUES (?, ?, ?, ?, ?, ?)';
protected $loadStatement = 'SELECT * FROM `*PREFIX*richdocuments_wopi` WHERE `token`= ?';
/*
* Given a fileId, generates a token
* and stores in the database.
* Returns the token.
*/
public function generateFileToken($fileId){
// Get the FS view of the current user.
$view = \OC\Files\Filesystem::getView();
// Get the virtual path (if the file is shared).
$path = $view->getPath($fileId);
if (!$view->is_file($path) || !$view->isUpdatable($path)) {
throw new \Exception('Invalid fileId.');
}
// Figure out the real owner, if not us.
$owner = $view->getOwner($path);
// Create a view into the owner's FS.
$view = new \OC\Files\View('/' . $owner . '/files');
// Find the real path.
$path = $view->getPath($fileId);
if (!$view->is_file($path)) {
throw new \Exception('Invalid fileId.');
}
$editor = \OC::$server->getUserSession()->getUser()->getUID();
$token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(32,
\OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
\OCP\Security\ISecureRandom::CHAR_DIGITS);
\OC::$server->getLogger()->debug('Issuing token for {editor} file {fileId} owned by {owner}, path {path}: {token}',
[ 'owner' => $owner, 'editor' => $editor, 'fileId' => $fileId, 'path' => $path, 'token' => $token ]);
$wopi = new \OCA\Richdocuments\Db\Wopi([
$owner,
$editor,
$fileId,
$path,
$token,
time() + self::TOKEN_LIFETIME_SECONDS
]);
if (!$wopi->insert()){
throw new \Exception('Failed to add wopi token into database');
}
return $token;
}
/*
* Given a token, validates it and
* constructs and validates the path.
* Returns the path, if valid, else false.
*/
public function getPathForToken($fileId, $token){
$wopi = new Wopi();
$row = $wopi->loadBy('token', $token)->getData();
\OC::$server->getLogger()->debug('Loaded WOPI Token record: {row}.', [ 'row' => $row ]);
if (count($row) == 0)
{
// Invalid token.
http_response_code(401);
return false;
}
//TODO: validate.
if ($row['expiry'] > time()){
// Expired token!
//http_response_code(404);
//$wopi->deleteBy('id', $row['id']);
//return false;
}
if ($row['fileid'] !== $fileId){
// File unknown / user unauthorized (for the requested file).
http_response_code(404);
return false;
}
$owner = $row['owner_uid'];
$view = new \OC\Files\View('/' . $owner . '/files');
$path = $row['path'];
if (!$view->is_file($path)) {
throw new \Exception('Invalid file path.');
}
$editor = $row['editor_uid'];
return array('owner' => $owner, 'editor' => $editor, 'path' => $path);
}
}
|