[cmd:netmount] fix #3138 OAuth not possible with CORS due to new ITP

This commit is contained in:
nao-pon
2020-03-30 15:44:47 +09:00
parent 962264dede
commit 2332f257ca
9 changed files with 244 additions and 124 deletions
+1
View File
@@ -420,6 +420,7 @@ elFinder.prototype.commands.download = function() {
if (html5dl) {
click(link.attr('href', url)
.attr('download', fm.escape(files[i].name))
.attr('target', '_blank')
.get(0)
);
} else {
+20 -5
View File
@@ -207,12 +207,27 @@ elFinder.prototype.commands.netmount = function() {
self.fm.bind('netmount', function(e) {
var d = e.data || null,
o = self.options;
o = self.options,
done = function() {
if (o[d.protocol] && typeof o[d.protocol].done == 'function') {
o[d.protocol].done(self.fm, d);
content.find('select,input').addClass('elfinder-tabstop');
self.dialog.elfinderdialog('tabstopsInit');
}
};
if (d && d.protocol) {
if (o[d.protocol] && typeof o[d.protocol].done == 'function') {
o[d.protocol].done(self.fm, d);
content.find('select,input').addClass('elfinder-tabstop');
self.dialog.elfinderdialog('tabstopsInit');
if (d.mode && d.mode === 'redirect') {
// To support of third-party cookie blocking (ITP) on CORS
// On iOS and iPadOS 13.4 and Safari 13.1 on macOS, the session cannot be continued when redirecting OAuth in CORS mode
self.fm.request({
data : {cmd : 'netmount', protocol : d.protocol, host: d.host, user : 'init', pass : 'return', options: d.options},
preventDefault : true
}).done(function(data) {
d = JSON.parse(data.body);
done();
});
} else {
done();
}
}
});
+5
View File
@@ -48,6 +48,7 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// elFinder::$netDrivers['dropbox2'] = 'Dropbox2';
// // Dropbox2 Netmount driver need next two settings. You can get at https://www.dropbox.com/developers/apps
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=dropbox2&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_DROPBOX_APPKEY', '');
// define('ELFINDER_DROPBOX_APPSECRET', '');
// ===============================================
@@ -59,6 +60,7 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// elFinder::$netDrivers['googledrive'] = 'GoogleDrive';
// // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_GOOGLEDRIVE_CLIENTID', '');
// define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
// // Required case when Google API is NOT added via composer
@@ -72,6 +74,7 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// elFinder::$netDrivers['googledrive'] = 'FlysystemGoogleDriveNetmount';
// // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_GOOGLEDRIVE_CLIENTID', '');
// define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
// // And "php/.tmp" directory must exist and be writable by PHP.
@@ -84,6 +87,7 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// elFinder::$netDrivers['onedrive'] = 'OneDrive';
// // GoogleDrive Netmount driver need next two settings. You can get at https://dev.onedrive.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL/netmount/onedrive/1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "/1" to "/ElementID"
// define('ELFINDER_ONEDRIVE_CLIENTID', '');
// define('ELFINDER_ONEDRIVE_CLIENTSECRET', '');
// ===============================================
@@ -94,6 +98,7 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// elFinder::$netDrivers['box'] = 'Box';
// // Box Netmount driver need next two settings. You can get at https://developer.box.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=box&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_BOX_CLIENTID', '');
// define('ELFINDER_BOX_CLIENTSECRET', '');
// ===============================================
+7 -7
View File
@@ -612,7 +612,7 @@ class elFinder
foreach (array_keys($this->commands[$_cmd]) as $_k) {
if (isset($_ps[$_i])) {
if (!isset($_GET[$_k])) {
$_GET[$_k] = $_ps[$_i];
$_GET[$_k] = $_ps[$_i++];
}
} else {
break;
@@ -1834,6 +1834,7 @@ class elFinder
$targets = $args['targets'];
$download = !empty($args['download']);
$h404 = 'HTTP/1.x 404 Not Found';
$CriOS = isset($_SERVER['HTTP_USER_AGENT'])? (strpos($_SERVER['HTTP_USER_AGENT'], 'CriOS') !== false) : false;
if (!$download) {
//1st: Return array contains download archive file info
@@ -1852,7 +1853,7 @@ class elFinder
$this->session->set('zipdl' . $uniqid, basename($path));
$result = array(
'zipdl' => array(
'file' => $uniqid,
'file' => $CriOS? basename($path) : $uniqid,
'name' => $name,
'mime' => $dlres['mime']
)
@@ -1868,21 +1869,20 @@ class elFinder
// Detect Chrome on iOS
// It has access twice on downloading
$CriOSinit = false;
$ua = isset($_SERVER['HTTP_USER_AGENT'])? $_SERVER['HTTP_USER_AGENT'] : '';
if (strpos($ua, 'CriOS') !== false) {
if ($CriOS) {
$accept = isset($_SERVER['HTTP_ACCEPT'])? $_SERVER['HTTP_ACCEPT'] : '';
if ($accept && $accept !== '*' && $accept !== '*/*') {
$CriOSinit = true;
}
}
// data check
if (count($targets) !== 4 || ($volume = $this->volume($targets[0])) == false || !($file = $this->session->get('zipdl' . $targets[1]))) {
if (count($targets) !== 4 || ($volume = $this->volume($targets[0])) == false || !($file = $CriOS? $targets[1] : $this->session->get('zipdl' . $targets[1]))) {
return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
}
$path = $volume->getTempPath() . DIRECTORY_SEPARATOR . basename($file);
// remove session data of "zipdl..."
$this->session->remove('zipdl' . $targets[1]);
if (!$CriOSinit) {
// remove session data of "zipdl..."
$this->session->remove('zipdl' . $targets[1]);
// register auto delete on shutdown
$GLOBALS['elFinderTempFiles'][$path] = true;
}
+40 -14
View File
@@ -126,15 +126,19 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
}
if ($options['user'] === 'init') {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code || $options['user'] === 'init') {
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url'] . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=1';
$client->setRedirectUri($callback);
if (isset($options['id'])) {
$callback = $options['url'] . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
$client->setRedirectUri($callback);
}
if (!$aToken && empty($_GET['code'])) {
if (!$aToken && empty($code)) {
$client->setScopes([Google_Service_Drive::DRIVE]);
if (!empty($options['offline'])) {
$client->setApprovalPrompt('force');
@@ -159,16 +163,38 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
return array('exit' => 'callback', 'out' => $out);
}
} else {
if (!empty($_GET['code'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$options['access_token'] = $aToken;
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount'
);
return array('exit' => 'callback', 'out' => $out);
if ($code) {
if (!empty($options['id'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($code);
$options['access_token'] = $aToken;
unset($options['code']);
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount'
);
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'googledrive',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code'=> $code
)
)),
'bind' => 'netmount'
);
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
}
$folders = [];
foreach ($service->files->listFiles([
+42 -34
View File
@@ -408,9 +408,11 @@ class elFinderVolumeBox extends elFinderVolumeDriver
*/
protected function _bd_curlExec($curl, $decodeOrParent = true, $headers = array(), $postData = array())
{
$headers = array_merge(array(
'Authorization: Bearer ' . $this->token->data->access_token,
), $headers);
if ($this->token) {
$headers = array_merge(array(
'Authorization: Bearer ' . $this->token->data->access_token,
), $headers);
}
$result = elFinder::curlExec($curl, array(), $headers, $postData);
@@ -679,7 +681,7 @@ class elFinderVolumeBox extends elFinderVolumeDriver
if (isset($options['id'])) {
$this->session->set('nodeId', $options['id']);
} elseif ($_id = $this->session->get('nodeId')) {
} else if ($_id = $this->session->get('nodeId')) {
$options['id'] = $_id;
$this->session->set('nodeId', $_id);
}
@@ -695,20 +697,41 @@ class elFinderVolumeBox extends elFinderVolumeDriver
return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
}
if (isset($_GET['code'])) {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code) {
try {
// Obtain the token using the code received by the Box.com API
$this->session->set('BoxTokens',
$this->_bd_obtainAccessToken($options['client_id'], $options['client_secret'], $_GET['code']));
if (!empty($options['id'])) {
// Obtain the token using the code received by the Box.com API
$this->session->set('BoxTokens',
$this->_bd_obtainAccessToken($options['client_id'], $options['client_secret'], $code));
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "box", "mode": "done", "reset": 1}',
'bind' => 'netmount',
);
return array('exit' => 'callback', 'out' => $out);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "box", "mode": "done", "reset": 1}',
'bind' => 'netmount'
);
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'box',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code'=> $code
)
)),
'bind' => 'netmount'
);
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
} catch (Exception $e) {
$out = array(
'node' => $options['id'],
@@ -750,27 +773,12 @@ class elFinderVolumeBox extends elFinderVolumeDriver
}
if ($result === false) {
$cdata = '';
$innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user');
$this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
foreach ($this->ARGS as $k => $v) {
if (!in_array($k, $innerKeys)) {
$cdata .= '&' . $k . '=' . rawurlencode($v);
}
}
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=box&host=box.com&user=init&pass=return&node=' . $options['id'] . $cdata;
$redirect = elFinder::getConnectorUrl();
$redirect .= (strpos($redirect, '?') !== false? '&' : '?') . 'cmd=netmount&protocol=box&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
try {
$this->session->set('BoxTokens', (object)array('token' => null));
$url = self::AUTH_URL . '?' . http_build_query(array('response_type' => 'code', 'client_id' => $options['client_id'], 'redirect_uri' => $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=box&host=1'));
$url .= '&oauth_callback=' . rawurlencode($callback);
$url = self::AUTH_URL . '?' . http_build_query(array('response_type' => 'code', 'client_id' => $options['client_id'], 'redirect_uri' => $redirect));
} catch (Exception $e) {
return array('exit' => true, 'body' => '{msg:errAccess}');
}
+46 -19
View File
@@ -330,10 +330,15 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=dropbox2&host=1';
if (!empty($options['id'])) {
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=dropbox2&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
}
if (!$aToken && empty($_GET['code'])) {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
$state = $itpCare? $options['state'] : (isset($_GET['state'])? $_GET['state'] : '');
if (!$aToken && empty($code)) {
$url = $authHelper->getAuthUrl($callback);
$html = '<input id="elf-volumedriver-dropbox2-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button">';
@@ -355,22 +360,44 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
return ['exit' => 'callback', 'out' => $out];
}
} else {
if (!empty($_GET['code']) && isset($_GET['state'])) {
// see https://github.com/kunalvarma05/dropbox-php-sdk/issues/115
$authHelper->getPersistentDataStore()->set('state', filter_var($_GET['state'], FILTER_SANITIZE_STRING));
$tokenObj = $authHelper->getAccessToken($_GET['code'], $_GET['state'], $callback);
$options['tokens'] = [
'access_token' => $tokenObj->getToken(),
'uid' => $tokenObj->getUid(),
];
$this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
return ['exit' => 'callback', 'out' => $out];
if ($code && $state) {
if (!empty($options['id'])) {
// see https://github.com/kunalvarma05/dropbox-php-sdk/issues/115
$authHelper->getPersistentDataStore()->set('state', filter_var($state, FILTER_SANITIZE_STRING));
$tokenObj = $authHelper->getAccessToken($code, $state, $callback);
$options['tokens'] = [
'access_token' => $tokenObj->getToken(),
'uid' => $tokenObj->getUid(),
];
unset($options['code'], $options['state']);
$this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = [
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'dropbox2',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code' => $code,
'state' => $state
)
)),
'bind' => 'netmount'
];
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
}
$path = $options['path'];
$folders = [];
+41 -16
View File
@@ -678,16 +678,20 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
}
}
if (isset($options['user']) && $options['user'] === 'init') {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code || (isset($options['user']) && $options['user'] === 'init')) {
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=1';
$client->setRedirectUri($callback);
if (isset($options['id'])) {
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
$client->setRedirectUri($callback);
}
if (!$aToken && empty($_GET['code'])) {
if (!$aToken && empty($code)) {
$client->setScopes([Google_Service_Drive::DRIVE]);
if (!empty($options['offline'])) {
$client->setApprovalPrompt('force');
@@ -714,17 +718,38 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
return ['exit' => 'callback', 'out' => $out];
}
} else {
if (!empty($_GET['code'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$options['access_token'] = $aToken;
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
return ['exit' => 'callback', 'out' => $out];
if ($code) {
if (!empty($options['id'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($code);
$options['access_token'] = $aToken;
unset($options['code']);
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'googledrive',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code'=> $code
)
)),
'bind' => 'netmount'
);
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
}
$path = $options['path'];
if ($path === '/') {
+42 -29
View File
@@ -134,7 +134,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
* @throws Exception Thrown if the redirect URI of this Client instance's
* state is not set
*/
protected function _od_obtainAccessToken($client_id, $client_secret, $code)
protected function _od_obtainAccessToken($client_id, $client_secret, $code, $nodeid)
{
if (null === $client_id) {
return 'The client ID must be set to call obtainAccessToken()';
@@ -144,6 +144,11 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
return 'The client Secret must be set to call obtainAccessToken()';
}
$redirect = elFinder::getConnectorUrl();
if (strpos($redirect, '/netmount/onedrive/') === false) {
$redirect .= '/netmount/onedrive/' . ($nodeid === 'elfinder'? '1' : $nodeid);
}
$url = self::TOKEN_URL;
$curl = curl_init();
@@ -151,7 +156,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$fields = http_build_query(
array(
'client_id' => $client_id,
'redirect_uri' => elFinder::getConnectorUrl(),
'redirect_uri' => $redirect,
'client_secret' => $client_secret,
'code' => $code,
'grant_type' => 'authorization_code',
@@ -753,19 +758,42 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
}
if (isset($_GET['code'])) {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code) {
try {
// Obtain the token using the code received by the OneDrive API
$this->session->set('OneDriveTokens',
$this->_od_obtainAccessToken($options['client_id'], $options['client_secret'], $_GET['code']));
if (!empty($options['id'])) {
debug($options['id']);
// Obtain the token using the code received by the OneDrive API
$this->session->set('OneDriveTokens',
$this->_od_obtainAccessToken($options['client_id'], $options['client_secret'], $code, $options['id']));
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "onedrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
);
return array('exit' => 'callback', 'out' => $out);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "onedrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
);
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'onedrive',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code'=> $code
)
)),
'bind' => 'netmount'
);
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
} catch (Exception $e) {
$out = array(
'node' => $options['id'],
@@ -812,20 +840,6 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
}
if ($result === false) {
$cdata = '';
$innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user');
$this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
foreach ($this->ARGS as $k => $v) {
if (!in_array($k, $innerKeys)) {
$cdata .= '&' . $k . '=' . rawurlencode($v);
}
}
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=onedrive&host=onedrive.com&user=init&pass=return&node=' . $options['id'] . $cdata;
try {
$this->session->set('OneDriveTokens', (object)array('token' => null));
@@ -835,14 +849,13 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$offline = ' offline_access';
}
$redirect_uri = $options['url'] . '/netmount/onedrive/1';
$redirect_uri = elFinder::getConnectorUrl() . '/netmount/onedrive/' . ($options['id'] === 'elfinder'? '1' : $options['id']);
$url = self::AUTH_URL
. '?client_id=' . urlencode($options['client_id'])
. '&scope=' . urlencode('files.readwrite.all' . $offline)
. '&response_type=code'
. '&redirect_uri=' . urlencode($redirect_uri);
$url .= '&oauth_callback=' . rawurlencode($callback);
} catch (Exception $e) {
return array('exit' => true, 'body' => '{msg:errAccess}');
}