Skip to content

Commit 87c8a71

Browse files
authored
Merge pull request #10068 from nextcloud/feature/1434/provisioning_profiles_for_dav
Add Apple Provisioning profile
2 parents 54a9730 + 9d285c4 commit 87c8a71

File tree

8 files changed

+738
-1
lines changed

8 files changed

+738
-1
lines changed

apps/dav/composer/composer/autoload_classmap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@
175175
'OCA\\DAV\\Migration\\Version1008Date20181105110300' => $baseDir . '/../lib/Migration/Version1008Date20181105110300.php',
176176
'OCA\\DAV\\Migration\\Version1008Date20181105112049' => $baseDir . '/../lib/Migration/Version1008Date20181105112049.php',
177177
'OCA\\DAV\\Migration\\Version1008Date20181114084440' => $baseDir . '/../lib/Migration/Version1008Date20181114084440.php',
178+
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
179+
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
178180
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
179181
'OCA\\DAV\\Server' => $baseDir . '/../lib/Server.php',
180182
'OCA\\DAV\\Settings\\CalDAVSettings' => $baseDir . '/../lib/Settings/CalDAVSettings.php',

apps/dav/composer/composer/autoload_static.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ class ComposerStaticInitDAV
190190
'OCA\\DAV\\Migration\\Version1008Date20181105110300' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181105110300.php',
191191
'OCA\\DAV\\Migration\\Version1008Date20181105112049' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181105112049.php',
192192
'OCA\\DAV\\Migration\\Version1008Date20181114084440' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181114084440.php',
193+
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
194+
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
193195
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
194196
'OCA\\DAV\\Server' => __DIR__ . '/..' . '/../lib/Server.php',
195197
'OCA\\DAV\\Settings\\CalDAVSettings' => __DIR__ . '/..' . '/../lib/Settings/CalDAVSettings.php',
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
/**
3+
* @copyright 2018, Georg Ehrke <[email protected]>
4+
*
5+
* @author Georg Ehrke <[email protected]>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OCA\DAV\Provisioning\Apple;
25+
26+
use OCP\AppFramework\Utility\ITimeFactory;
27+
use Sabre\DAV\Exception\Forbidden;
28+
use Sabre\DAV\INode;
29+
use Sabre\DAV\IProperties;
30+
use Sabre\DAV\PropPatch;
31+
32+
class AppleProvisioningNode implements INode, IProperties {
33+
34+
const FILENAME = 'apple-provisioning.mobileconfig';
35+
36+
protected $timeFactory;
37+
38+
/**
39+
* @param ITimeFactory $timeFactory
40+
*/
41+
public function __construct(ITimeFactory $timeFactory) {
42+
$this->timeFactory = $timeFactory;
43+
}
44+
45+
/**
46+
* @return string
47+
*/
48+
public function getName() {
49+
return self::FILENAME;
50+
}
51+
52+
53+
public function setName($name) {
54+
throw new Forbidden('Renaming ' . self::FILENAME . ' is forbidden');
55+
}
56+
57+
/**
58+
* @return null
59+
*/
60+
public function getLastModified() {
61+
return null;
62+
}
63+
64+
/**
65+
* @throws Forbidden
66+
*/
67+
public function delete() {
68+
throw new Forbidden(self::FILENAME . ' may not be deleted.');
69+
}
70+
71+
/**
72+
* @param array $properties
73+
* @return array
74+
*/
75+
public function getProperties($properties) {
76+
$datetime = $this->timeFactory->getDateTime();
77+
78+
return [
79+
'{DAV:}getcontentlength' => 42,
80+
'{DAV:}getlastmodified' => $datetime->format(\DateTime::RFC2822),
81+
];
82+
}
83+
84+
/**
85+
* @param PropPatch $propPatch
86+
* @throws Forbidden
87+
*/
88+
public function propPatch(PropPatch $propPatch) {
89+
throw new Forbidden(self::FILENAME . '\'s properties may not be altered.');
90+
}
91+
}
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
<?php
2+
/**
3+
* @copyright 2018, Georg Ehrke <[email protected]>
4+
*
5+
* @author Georg Ehrke <[email protected]>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OCA\DAV\Provisioning\Apple;
25+
26+
use OCP\IL10N;
27+
use OCP\IRequest;
28+
use OCP\IURLGenerator;
29+
use OCP\IUserSession;
30+
use Sabre\DAV\Server;
31+
use Sabre\DAV\ServerPlugin;
32+
use Sabre\HTTP\RequestInterface;
33+
use Sabre\HTTP\ResponseInterface;
34+
35+
class AppleProvisioningPlugin extends ServerPlugin {
36+
37+
/**
38+
* @var Server
39+
*/
40+
protected $server;
41+
42+
/**
43+
* @var IURLGenerator
44+
*/
45+
protected $urlGenerator;
46+
47+
/**
48+
* @var IUserSession
49+
*/
50+
protected $userSession;
51+
52+
/**
53+
* @var \OC_Defaults
54+
*/
55+
protected $themingDefaults;
56+
57+
/**
58+
* @var IRequest
59+
*/
60+
protected $request;
61+
62+
/**
63+
* @var IL10N
64+
*/
65+
protected $l10n;
66+
67+
/**
68+
* @var \closure
69+
*/
70+
protected $uuidClosure;
71+
72+
/**
73+
* AppleProvisioningPlugin constructor.
74+
*
75+
* @param IUserSession $userSession
76+
* @param IURLGenerator $urlGenerator
77+
* @param \OC_Defaults $themingDefaults
78+
* @param IRequest $request
79+
* @param IL10N $l10n
80+
* @param \closure $uuidClosure
81+
*/
82+
public function __construct(IUserSession $userSession, IURLGenerator $urlGenerator,
83+
\OC_Defaults $themingDefaults, IRequest $request,
84+
IL10N $l10n, \closure $uuidClosure) {
85+
$this->userSession = $userSession;
86+
$this->urlGenerator = $urlGenerator;
87+
$this->themingDefaults = $themingDefaults;
88+
$this->request = $request;
89+
$this->l10n = $l10n;
90+
$this->uuidClosure = $uuidClosure;
91+
}
92+
93+
/**
94+
* @param Server $server
95+
*/
96+
public function initialize(Server $server) {
97+
$this->server = $server;
98+
$this->server->on('method:GET', [$this, 'httpGet'], 90);
99+
}
100+
101+
/**
102+
* @param RequestInterface $request
103+
* @param ResponseInterface $response
104+
* @return boolean
105+
*/
106+
public function httpGet(RequestInterface $request, ResponseInterface $response):bool {
107+
if ($request->getPath() !== 'provisioning/' . AppleProvisioningNode::FILENAME) {
108+
return true;
109+
}
110+
111+
$user = $this->userSession->getUser();
112+
if (!$user) {
113+
return true;
114+
}
115+
116+
$serverProtocol = $this->request->getServerProtocol();
117+
$useSSL = ($serverProtocol === 'https');
118+
119+
if (!$useSSL) {
120+
$response->setStatus(200);
121+
$response->setHeader('Content-Type', 'text/plain; charset=utf-8');
122+
$response->setBody($this->l10n->t('Your %s needs to be configured to use HTTPS in order to use CalDAV and CardDAV with iOS/macOS.', [$this->themingDefaults->getName()]));
123+
124+
return false;
125+
}
126+
127+
$absoluteURL = $request->getAbsoluteUrl();
128+
$parsedUrl = parse_url($absoluteURL);
129+
if (isset($parsedUrl['port'])) {
130+
$serverPort = (int) $parsedUrl['port'];
131+
} else {
132+
$serverPort = 443;
133+
}
134+
$server_url = $parsedUrl['host'];
135+
136+
$description = $this->themingDefaults->getName();
137+
$userId = $user->getUID();
138+
139+
$reverseDomain = implode('.', array_reverse(explode('.', $parsedUrl['host'])));
140+
141+
$caldavUUID = call_user_func($this->uuidClosure);
142+
$carddavUUID = call_user_func($this->uuidClosure);
143+
$profileUUID = call_user_func($this->uuidClosure);
144+
145+
$caldavIdentifier = $reverseDomain . '.' . $caldavUUID;
146+
$carddavIdentifier = $reverseDomain . '.' . $carddavUUID;
147+
$profileIdentifier = $reverseDomain . '.' . $profileUUID;
148+
149+
$caldavDescription = $this->l10n->t('Configures a CalDAV account');
150+
$caldavDisplayname = $description . ' CalDAV';
151+
$carddavDescription = $this->l10n->t('Configures a CardDAV account');
152+
$carddavDisplayname = $description . ' CardDAV';
153+
154+
$filename = $userId . '-' . AppleProvisioningNode::FILENAME;
155+
156+
$xmlSkeleton = $this->getTemplate();
157+
$body = vsprintf($xmlSkeleton, array_map(function($v) {
158+
return \htmlspecialchars($v, ENT_XML1, 'UTF-8');
159+
}, [
160+
$description,
161+
$server_url,
162+
$userId,
163+
$serverPort,
164+
$caldavDescription,
165+
$caldavDisplayname,
166+
$caldavIdentifier,
167+
$caldavUUID,
168+
$description,
169+
$server_url,
170+
$userId,
171+
$serverPort,
172+
$carddavDescription,
173+
$carddavDisplayname,
174+
$carddavIdentifier,
175+
$carddavUUID,
176+
$description,
177+
$profileIdentifier,
178+
$profileUUID
179+
]
180+
));
181+
182+
$response->setStatus(200);
183+
$response->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
184+
$response->setHeader('Content-Type', 'application/xml; charset=utf-8');
185+
$response->setBody($body);
186+
187+
return false;
188+
}
189+
190+
/**
191+
* @return string
192+
*/
193+
private function getTemplate():string {
194+
return <<<EOF
195+
<?xml version="1.0" encoding="UTF-8"?>
196+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
197+
<plist version="1.0">
198+
<dict>
199+
<key>PayloadContent</key>
200+
<array>
201+
<dict>
202+
<key>CalDAVAccountDescription</key>
203+
<string>%s</string>
204+
<key>CalDAVHostName</key>
205+
<string>%s</string>
206+
<key>CalDAVUsername</key>
207+
<string>%s</string>
208+
<key>CalDAVUseSSL</key>
209+
<true/>
210+
<key>CalDAVPort</key>
211+
<integer>%s</integer>
212+
<key>PayloadDescription</key>
213+
<string>%s</string>
214+
<key>PayloadDisplayName</key>
215+
<string>%s</string>
216+
<key>PayloadIdentifier</key>
217+
<string>%s</string>
218+
<key>PayloadType</key>
219+
<string>com.apple.caldav.account</string>
220+
<key>PayloadUUID</key>
221+
<string>%s</string>
222+
<key>PayloadVersion</key>
223+
<integer>1</integer>
224+
</dict>
225+
<dict>
226+
<key>CardDAVAccountDescription</key>
227+
<string>%s</string>
228+
<key>CardDAVHostName</key>
229+
<string>%s</string>
230+
<key>CardDAVUsername</key>
231+
<string>%s</string>
232+
<key>CardDAVUseSSL</key>
233+
<true/>
234+
<key>CardDAVPort</key>
235+
<integer>%s</integer>
236+
<key>PayloadDescription</key>
237+
<string>%s</string>
238+
<key>PayloadDisplayName</key>
239+
<string>%s</string>
240+
<key>PayloadIdentifier</key>
241+
<string>%s</string>
242+
<key>PayloadType</key>
243+
<string>com.apple.carddav.account</string>
244+
<key>PayloadUUID</key>
245+
<string>%s</string>
246+
<key>PayloadVersion</key>
247+
<integer>1</integer>
248+
</dict>
249+
</array>
250+
<key>PayloadDisplayName</key>
251+
<string>%s</string>
252+
<key>PayloadIdentifier</key>
253+
<string>%s</string>
254+
<key>PayloadRemovalDisallowed</key>
255+
<false/>
256+
<key>PayloadType</key>
257+
<string>Configuration</string>
258+
<key>PayloadUUID</key>
259+
<string>%s</string>
260+
<key>PayloadVersion</key>
261+
<integer>1</integer>
262+
</dict>
263+
</plist>
264+
265+
EOF;
266+
}
267+
}

0 commit comments

Comments
 (0)