diff options
36 files changed, 1401 insertions, 847 deletions
diff --git a/apps/files_encryption/ajax/mode.php b/apps/files_encryption/ajax/mode.php deleted file mode 100644 index 64c5be94401..00000000000 --- a/apps/files_encryption/ajax/mode.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -/**
- * Copyright (c) 2012, Bjoern Schiessle <schiessle@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or later.
- * See the COPYING-README file.
- */ -
-use OCA\Encryption\Keymanager; - -OCP\JSON::checkAppEnabled('files_encryption');
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
- -$mode = $_POST['mode']; -$changePasswd = false; -$passwdChanged = false; - -if ( isset($_POST['newpasswd']) && isset($_POST['oldpasswd']) ) { - $oldpasswd = $_POST['oldpasswd']; - $newpasswd = $_POST['newpasswd']; - $changePasswd = true; - $passwdChanged = Keymanager::changePasswd($oldpasswd, $newpasswd); -} - -$query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" );
-$result = $query->execute(array(\OCP\User::getUser()));
- -if ($result->fetchRow()){ - $query = OC_DB::prepare( 'UPDATE *PREFIX*encryption SET mode = ? WHERE uid = ?' ); -} else { - $query = OC_DB::prepare( 'INSERT INTO *PREFIX*encryption ( mode, uid ) VALUES( ?, ? )' ); -} - -if ( (!$changePasswd || $passwdChanged) && $query->execute(array($mode, \OCP\User::getUser())) ) { - OCP\JSON::success(); -} else { - OCP\JSON::error(); -}
\ No newline at end of file diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index f83109a18ea..08728622525 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -43,6 +43,6 @@ if ( } -// Reguster settings scripts +// Register settings scripts OCP\App::registerAdmin( 'files_encryption', 'settings' ); -OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );
\ No newline at end of file +OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php index 8bdeee0937b..7e4f677ce9d 100644 --- a/apps/files_encryption/hooks/hooks.php +++ b/apps/files_encryption/hooks/hooks.php @@ -165,16 +165,6 @@ class Hooks { * @brief
*/
public static function postShared( $params ) {
-
- // Delete existing catfile
- Keymanager::deleteFileKey( );
-
- // Generate new catfile and env keys
- Crypt::multiKeyEncrypt( $plainContent, $publicKeys );
-
- // Save env keys to user folders
-
-
}
/**
diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js deleted file mode 100644 index 1a53e99d2b4..00000000000 --- a/apps/files_encryption/js/settings-personal.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2012, Bjoern Schiessle <schiessle@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - -$(document).ready(function(){ - $('input[name=encryption_mode]').change(function(){ - var prevmode = document.getElementById('prev_encryption_mode').value - var client=$('input[value="client"]:checked').val() - ,server=$('input[value="server"]:checked').val() - ,user=$('input[value="user"]:checked').val() - ,none=$('input[value="none"]:checked').val() - if (client) { - $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'client' }); - if (prevmode == 'server') { - OC.dialogs.info(t('encryption', 'Please switch to your ownCloud client and change your encryption password to complete the conversion.'), t('encryption', 'switched to client side encryption')); - } - } else if (server) { - if (prevmode == 'client') { - OC.dialogs.form([{text:'Login password', name:'newpasswd', type:'password'},{text:'Encryption password used on the client', name:'oldpasswd', type:'password'}],t('encryption', 'Change encryption password to login password'), function(data) { - $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'server', newpasswd: data[0].value, oldpasswd: data[1].value }, function(result) { - if (result.status != 'success') { - document.getElementById(prevmode+'_encryption').checked = true; - OC.dialogs.alert(t('encryption', 'Please check your passwords and try again.'), t('encryption', 'Could not change your file encryption password to your login password')) - } else { - console.log("alles super"); - } - }, true); - }); - } else { - $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'server' }); - } - } else { - $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'none' }); - } - }) -})
\ No newline at end of file diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js index 60563bde859..0be857bb73e 100644 --- a/apps/files_encryption/js/settings.js +++ b/apps/files_encryption/js/settings.js @@ -9,38 +9,11 @@ $(document).ready(function(){ $('#encryption_blacklist').multiSelect({ oncheck:blackListChange, onuncheck:blackListChange, - createText:'...', + createText:'...' }); function blackListChange(){ var blackList=$('#encryption_blacklist').val().join(','); OC.AppConfig.setValue('files_encryption','type_blacklist',blackList); } - - //TODO: Handle switch between client and server side encryption - $('input[name=encryption_mode]').change(function(){ - var client=$('input[value="client"]:checked').val() - ,server=$('input[value="server"]:checked').val() - ,user=$('input[value="user"]:checked').val() - ,none=$('input[value="none"]:checked').val() - ,disable=false - if (client) { - OC.AppConfig.setValue('files_encryption','mode','client'); - disable = true; - } else if (server) { - OC.AppConfig.setValue('files_encryption','mode','server'); - disable = true; - } else if (user) { - OC.AppConfig.setValue('files_encryption','mode','user'); - disable = true; - } else { - OC.AppConfig.setValue('files_encryption','mode','none'); - } - if (disable) { - document.getElementById('server_encryption').disabled = true; - document.getElementById('client_encryption').disabled = true; - document.getElementById('user_encryption').disabled = true; - document.getElementById('none_encryption').disabled = true; - } - }) })
\ No newline at end of file diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index d00f71b6141..c7a414c5080 100755 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -4,8 +4,8 @@ * ownCloud
*
* @author Sam Tuke, Frank Karlitschek, Robin Appelman
- * @copyright 2012 Sam Tuke samtuke@owncloud.com,
- * Robin Appelman icewind@owncloud.com, Frank Karlitschek
+ * @copyright 2012 Sam Tuke samtuke@owncloud.com,
+ * Robin Appelman icewind@owncloud.com, Frank Karlitschek
* frank@owncloud.org
*
* This library is free software; you can redistribute it and/or
@@ -47,15 +47,15 @@ class Crypt { public static function mode( $user = null ) {
return 'server';
-
+
}
-
- /**
- * @brief Create a new encryption keypair
- * @return array publicKey, privatekey
- */
+
+ /**
+ * @brief Create a new encryption keypair
+ * @return array publicKey, privatekey
+ */
public static function createKeypair() {
-
+
$res = openssl_pkey_new();
// Get private key
@@ -63,570 +63,543 @@ class Crypt { // Get public key
$publicKey = openssl_pkey_get_details( $res );
-
+
$publicKey = $publicKey['key'];
-
+
return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) );
-
+
}
-
- /**
- * @brief Add arbitrary padding to encrypted data
- * @param string $data data to be padded
- * @return padded data
- * @note In order to end up with data exactly 8192 bytes long we must
- * add two letters. It is impossible to achieve exactly 8192 length
- * blocks with encryption alone, hence padding is added to achieve the
- * required length.
- */
+
+ /**
+ * @brief Add arbitrary padding to encrypted data
+ * @param string $data data to be padded
+ * @return padded data
+ * @note In order to end up with data exactly 8192 bytes long we must
+ * add two letters. It is impossible to achieve exactly 8192 length
+ * blocks with encryption alone, hence padding is added to achieve the
+ * required length.
+ */
public static function addPadding( $data ) {
-
+
$padded = $data . 'xx';
-
+
return $padded;
-
+
}
-
- /**
- * @brief Remove arbitrary padding to encrypted data
- * @param string $padded padded data to remove padding from
- * @return unpadded data on success, false on error
- */
+
+ /**
+ * @brief Remove arbitrary padding to encrypted data
+ * @param string $padded padded data to remove padding from
+ * @return unpadded data on success, false on error
+ */
public static function removePadding( $padded ) {
-
+
if ( substr( $padded, -2 ) == 'xx' ) {
-
+
$data = substr( $padded, 0, -2 );
-
+
return $data;
-
+
} else {
-
+
// TODO: log the fact that unpadded data was submitted for removal of padding
return false;
-
+
}
-
+
}
-
- /**
- * @brief Check if a file's contents contains an IV and is symmetrically encrypted
- * @return true / false
- * @note see also OCA\Encryption\Util->isEncryptedPath()
- */
+
+ /**
+ * @brief Check if a file's contents contains an IV and is symmetrically encrypted
+ * @return true / false
+ * @note see also OCA\Encryption\Util->isEncryptedPath()
+ */
public static function isCatfile( $content ) {
-
+
+ if ( !$content ) {
+
+ return false;
+
+ }
+
$noPadding = self::removePadding( $content );
-
+
// Fetch encryption metadata from end of file
$meta = substr( $noPadding, -22 );
-
+
// Fetch IV from end of file
$iv = substr( $meta, -16 );
-
+
// Fetch identifier from start of metadata
$identifier = substr( $meta, 0, 6 );
-
+
if ( $identifier == '00iv00') {
-
+
return true;
-
+
} else {
-
+
return false;
-
+
}
-
+
}
-
+
/**
* Check if a file is encrypted according to database file cache
* @param string $path
* @return bool
*/
public static function isEncryptedMeta( $path ) {
-
+
// TODO: Use DI to get \OC\Files\Filesystem out of here
-
+
// Fetch all file metadata from DB
$metadata = \OC\Files\Filesystem::getFileInfo( $path, '' );
-
+
// Return encryption status
return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted'];
-
+
}
-
- /**
- * @brief Check if a file is encrypted via legacy system
- * @param string $relPath The path of the file, relative to user/data;
- * e.g. filename or /Docs/filename, NOT admin/files/filename
- * @return true / false
- */
+
+ /**
+ * @brief Check if a file is encrypted via legacy system
+ * @param string $relPath The path of the file, relative to user/data;
+ * e.g. filename or /Docs/filename, NOT admin/files/filename
+ * @return true / false
+ */
public static function isLegacyEncryptedContent( $data, $relPath ) {
-
+
// Fetch all file metadata from DB
$metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' );
-
+
// If a file is flagged with encryption in DB, but isn't a
// valid content + IV combination, it's probably using the
// legacy encryption system
- if (
- isset( $metadata['encrypted'] )
- and $metadata['encrypted'] === true
- and ! self::isCatfile( $data )
+ if (
+ isset( $metadata['encrypted'] )
+ and $metadata['encrypted'] === true
+ and ! self::isCatfile( $data )
) {
-
+
return true;
-
+
} else {
-
+
return false;
-
+
}
-
+
}
-
- /**
- * @brief Symmetrically encrypt a string
- * @returns encrypted file
- */
+
+ /**
+ * @brief Symmetrically encrypt a string
+ * @returns encrypted file
+ */
public static function encrypt( $plainContent, $iv, $passphrase = '' ) {
-
+
if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
return $encryptedContent;
-
+
} else {
-
+
\OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR );
-
+
return false;
-
+
}
-
+
}
-
- /**
- * @brief Symmetrically decrypt a string
- * @returns decrypted file
- */
+
+ /**
+ * @brief Symmetrically decrypt a string
+ * @returns decrypted file
+ */
public static function decrypt( $encryptedContent, $iv, $passphrase ) {
-
+
if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
return $plainContent;
-
-
+
+
} else {
-
+
throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' );
-
- return false;
-
+
}
-
+
}
-
- /**
- * @brief Concatenate encrypted data with its IV and padding
- * @param string $content content to be concatenated
- * @param string $iv IV to be concatenated
- * @returns string concatenated content
- */
+
+ /**
+ * @brief Concatenate encrypted data with its IV and padding
+ * @param string $content content to be concatenated
+ * @param string $iv IV to be concatenated
+ * @returns string concatenated content
+ */
public static function concatIv ( $content, $iv ) {
-
+
$combined = $content . '00iv00' . $iv;
-
+
return $combined;
-
+
}
-
- /**
- * @brief Split concatenated data and IV into respective parts
- * @param string $catFile concatenated data to be split
- * @returns array keys: encrypted, iv
- */
+
+ /**
+ * @brief Split concatenated data and IV into respective parts
+ * @param string $catFile concatenated data to be split
+ * @returns array keys: encrypted, iv
+ */
public static function splitIv ( $catFile ) {
-
+
// Fetch encryption metadata from end of file
$meta = substr( $catFile, -22 );
-
+
// Fetch IV from end of file
$iv = substr( $meta, -16 );
-
+
// Remove IV and IV identifier text to expose encrypted content
$encrypted = substr( $catFile, 0, -22 );
-
+
$split = array(
'encrypted' => $encrypted
- , 'iv' => $iv
+ , 'iv' => $iv
);
-
+
return $split;
-
+
}
-
- /**
- * @brief Symmetrically encrypts a string and returns keyfile content
- * @param $plainContent content to be encrypted in keyfile
- * @returns encrypted content combined with IV
- * @note IV need not be specified, as it will be stored in the returned keyfile
- * and remain accessible therein.
- */
+
+ /**
+ * @brief Symmetrically encrypts a string and returns keyfile content
+ * @param $plainContent content to be encrypted in keyfile
+ * @returns encrypted content combined with IV
+ * @note IV need not be specified, as it will be stored in the returned keyfile
+ * and remain accessible therein.
+ */
public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) {
-
+
if ( !$plainContent ) {
-
+
return false;
-
+
}
-
+
$iv = self::generateIv();
-
+
if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) {
-
- // Combine content to encrypt with IV identifier and actual IV
- $catfile = self::concatIv( $encryptedContent, $iv );
-
- $padded = self::addPadding( $catfile );
-
- return $padded;
-
+
+ // Combine content to encrypt with IV identifier and actual IV
+ $catfile = self::concatIv( $encryptedContent, $iv );
+
+ $padded = self::addPadding( $catfile );
+
+ return $padded;
+
} else {
-
+
\OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR );
-
+
return false;
-
+
}
-
+
}
/**
- * @brief Symmetrically decrypts keyfile content
- * @param string $source
- * @param string $target
- * @param string $key the decryption key
- * @returns decrypted content
- *
- * This function decrypts a file
- */
+ * @brief Symmetrically decrypts keyfile content
+ * @param string $source
+ * @param string $target
+ * @param string $key the decryption key
+ * @returns decrypted content
+ *
+ * This function decrypts a file
+ */
public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) {
-
+
if ( !$keyfileContent ) {
-
+
throw new \Exception( 'Encryption library: no data provided for decryption' );
-
+
}
-
+
// Remove padding
$noPadding = self::removePadding( $keyfileContent );
-
+
// Split into enc data and catfile
$catfile = self::splitIv( $noPadding );
-
+
if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) {
-
+
return $plainContent;
-
+
}
-
+
}
-
+
/**
- * @brief Creates symmetric keyfile content using a generated key
- * @param string $plainContent content to be encrypted
- * @returns array keys: key, encrypted
- * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
- *
- * This function decrypts a file
- */
+ * @brief Creates symmetric keyfile content using a generated key
+ * @param string $plainContent content to be encrypted
+ * @returns array keys: key, encrypted
+ * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
+ *
+ * This function decrypts a file
+ */
public static function symmetricEncryptFileContentKeyfile( $plainContent ) {
-
+
$key = self::generateKey();
-
+
if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) {
-
+
return array(
'key' => $key
- , 'encrypted' => $encryptedContent
+ , 'encrypted' => $encryptedContent
);
-
+
} else {
-
+
return false;
-
+
}
-
+
}
-
+
/**
- * @brief Create asymmetrically encrypted keyfile content using a generated key
- * @param string $plainContent content to be encrypted
- * @returns array keys: key, encrypted
- * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
- *
- * This function decrypts a file
- */
+ * @brief Create asymmetrically encrypted keyfile content using a generated key
+ * @param string $plainContent content to be encrypted
+ * @returns array keys: key, encrypted
+ * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
+ *
+ * This function decrypts a file
+ */
public static function multiKeyEncrypt( $plainContent, array $publicKeys ) {
-
+
// Set empty vars to be set by openssl by reference
$sealed = '';
$envKeys = array();
-
+
if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {
-
+
return array(
'keys' => $envKeys
- , 'encrypted' => $sealed
+ , 'encrypted' => $sealed
);
-
+
} else {
-
+
return false;
-
+
}
-
+
}
-
+
/**
- * @brief Asymmetrically encrypt a file using multiple public keys
- * @param string $plainContent content to be encrypted
- * @returns string $plainContent decrypted string
- * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
- *
- * This function decrypts a file
- */
+ * @brief Asymmetrically encrypt a file using multiple public keys
+ * @param string $plainContent content to be encrypted
+ * @returns string $plainContent decrypted string
+ * @note symmetricDecryptFileContent() can be used to decrypt files created using this method
+ *
+ * This function decrypts a file
+ */
public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) {
-
+
if ( !$encryptedContent ) {
-
+
return false;
-
+
}
-
+
if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) {
-
+
return $plainContent;
-
+
} else {
-
+
\OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR );
-
+
return false;
-
+
}
-
+
}
-
- /**
- * @brief Asymetrically encrypt a string using a public key
- * @returns encrypted file
- */
+
+ /**
+ * @brief Asymmetrically encrypt a string using a public key
+ * @returns encrypted file
+ */
public static function keyEncrypt( $plainContent, $publicKey ) {
-
+
openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey );
-
+
return $encryptedContent;
-
+
}
-
- /**
- * @brief Asymetrically decrypt a file using a private key
- * @returns decrypted file
- */
+
+ /**
+ * @brief Asymetrically decrypt a file using a private key
+ * @returns decrypted file
+ */
public static function keyDecrypt( $encryptedContent, $privatekey ) {
-
+
openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey );
-
+
return $plainContent;
-
+
}
- /**
- * @brief Encrypts content symmetrically and generates keyfile asymmetrically
- * @returns array containing catfile and new keyfile.
- * keys: data, key
- * @note this method is a wrapper for combining other crypt class methods
- */
+ /**
+ * @brief Encrypts content symmetrically and generates keyfile asymmetrically
+ * @returns array containing catfile and new keyfile.
+ * keys: data, key
+ * @note this method is a wrapper for combining other crypt class methods
+ */
public static function keyEncryptKeyfile( $plainContent, $publicKey ) {
-
+
// Encrypt plain data, generate keyfile & encrypted file
$cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent );
-
+
// Encrypt keyfile
$cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey );
-
+
return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey );
-
+
}
-
- /**
- * @brief Takes catfile, keyfile, and private key, and
- * performs decryption
- * @returns decrypted content
- * @note this method is a wrapper for combining other crypt class methods
- */
+
+ /**
+ * @brief Takes catfile, keyfile, and private key, and
+ * performs decryption
+ * @returns decrypted content
+ * @note this method is a wrapper for combining other crypt class methods
+ */
public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) {
-
+
// Decrypt the keyfile with the user's private key
$decryptedKeyfile = self::keyDecrypt( $keyfile, $privateKey );
-
+
// Decrypt the catfile symmetrically using the decrypted keyfile
$decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKeyfile );
-
+
return $decryptedData;
-
+
}
-
+
/**
- * @brief Symmetrically encrypt a file by combining encrypted component data blocks
- */
+ * @brief Symmetrically encrypt a file by combining encrypted component data blocks
+ */
public static function symmetricBlockEncryptFileContent( $plainContent, $key ) {
-
+
$crypted = '';
-
+
$remaining = $plainContent;
-
+
$testarray = array();
-
+
while( strlen( $remaining ) ) {
-
+
//echo "\n\n\$block = ".substr( $remaining, 0, 6126 );
-
+
// Encrypt a chunk of unencrypted data and add it to the rest
$block = self::symmetricEncryptFileContent( substr( $remaining, 0, 6126 ), $key );
-
+
$padded = self::addPadding( $block );
-
+
$crypted .= $block;
-
+
$testarray[] = $block;
-
+
// Remove the data already encrypted from remaining unencrypted data
$remaining = substr( $remaining, 6126 );
-
+
}
-
- //echo "hags ";
-
- //echo "\n\n\n\$crypted = $crypted\n\n\n";
-
- //print_r($testarray);
-
+
return $crypted;
}
/**
- * @brief Symmetrically decrypt a file by combining encrypted component data blocks
- */
+ * @brief Symmetrically decrypt a file by combining encrypted component data blocks
+ */
public static function symmetricBlockDecryptFileContent( $crypted, $key ) {
-
+
$decrypted = '';
-
+
$remaining = $crypted;
-
+
$testarray = array();
-
+
while( strlen( $remaining ) ) {
-
+
$testarray[] = substr( $remaining, 0, 8192 );
-
+
// Decrypt a chunk of unencrypted data and add it to the rest
$decrypted .= self::symmetricDecryptFileContent( $remaining, $key );
-
+
// Remove the data already encrypted from remaining unencrypted data
$remaining = substr( $remaining, 8192 );
-
+
}
-
- //echo "\n\n\$testarray = "; print_r($testarray);
-
+
return $decrypted;
-
+
}
-
- /**
- * @brief Generates a pseudo random initialisation vector
- * @return String $iv generated IV
- */
+
+ /**
+ * @brief Generates a pseudo random initialisation vector
+ * @return String $iv generated IV
+ */
public static function generateIv() {
-
+
if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) {
-
+
if ( !$strong ) {
-
+
// If OpenSSL indicates randomness is insecure, log error
\OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN );
-
+
}
-
+
// We encode the iv purely for string manipulation
// purposes - it gets decoded before use
$iv = base64_encode( $random );
-
+
return $iv;
-
+
} else {
-
- throw new Exception( 'Generating IV failed' );
-
+
+ throw new \Exception( 'Generating IV failed' );
+
}
-
+
}
-
- /**
- * @brief Generate a pseudo random 1024kb ASCII key
- * @returns $key Generated key
- */
+
+ /**
+ * @brief Generate a pseudo random 1024kb ASCII key
+ * @returns $key Generated key
+ */
public static function generateKey() {
-
+
// Generate key
if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) {
-
+
if ( !$strong ) {
-
+
// If OpenSSL indicates randomness is insecure, log error
- throw new Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' );
-
+ throw new \Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' );
+
}
-
+
return $key;
-
+
} else {
-
+
return false;
-
- }
-
- }
- public static function changekeypasscode( $oldPassword, $newPassword ) {
-
- if ( \OCP\User::isLoggedIn() ) {
-
- $key = Keymanager::getPrivateKey( $user, $view );
-
- if ( ( $key = Crypt::symmetricDecryptFileContent($key,$oldpasswd) ) ) {
-
- if ( ( $key = Crypt::symmetricEncryptFileContent( $key, $newpasswd ) ) ) {
-
- Keymanager::setPrivateKey( $key );
-
- return true;
- }
-
- }
-
}
-
- return false;
-
+
}
-
+
/**
* @brief Get the blowfish encryption handeler for a key
* @param $key string (optional)
@@ -635,21 +608,21 @@ class Crypt { * if the key is left out, the default handeler will be used
*/
public static function getBlowfish( $key = '' ) {
-
+
if ( $key ) {
-
+
return new \Crypt_Blowfish( $key );
-
+
} else {
-
+
return false;
-
+
}
-
+
}
-
+
public static function legacyCreateKey( $passphrase ) {
-
+
// Generate a random integer
$key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 );
@@ -657,9 +630,9 @@ class Crypt { $legacyEncKey = self::legacyEncrypt( $key, $passphrase );
return $legacyEncKey;
-
+
}
-
+
/**
* @brief encrypts content using legacy blowfish system
* @param $content the cleartext message you want to encrypt
@@ -669,54 +642,54 @@ class Crypt { * This function encrypts an content
*/
public static function legacyEncrypt( $content, $passphrase = '' ) {
-
+
$bf = self::getBlowfish( $passphrase );
-
+
return $bf->encrypt( $content );
-
+
}
-
+
/**
- * @brief decrypts content using legacy blowfish system
- * @param $content the cleartext message you want to decrypt
- * @param $key the encryption key (optional)
- * @returns cleartext content
- *
- * This function decrypts an content
- */
+ * @brief decrypts content using legacy blowfish system
+ * @param $content the cleartext message you want to decrypt
+ * @param $key the encryption key (optional)
+ * @returns cleartext content
+ *
+ * This function decrypts an content
+ */
public static function legacyDecrypt( $content, $passphrase = '' ) {
-
+
$bf = self::getBlowfish( $passphrase );
-
+
$decrypted = $bf->decrypt( $content );
-
+
$trimmed = rtrim( $decrypted, "\0" );
-
+
return $trimmed;
-
+
}
-
+
public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase ) {
-
+
$decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase );
-
+
$recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey );
-
+
return $recrypted;
-
+
}
-
+
/**
- * @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV
- * @param $legacyContent the legacy encrypted content to re-encrypt
- * @returns cleartext content
- *
- * This function decrypts an content
- */
+ * @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV
+ * @param $legacyContent the legacy encrypted content to re-encrypt
+ * @returns cleartext content
+ *
+ * This function decrypts an content
+ */
public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) {
-
+
// TODO: write me
-
+
}
-
+
}
\ No newline at end of file diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php index 43af70dacc2..95587797154 100755 --- a/apps/files_encryption/lib/keymanager.php +++ b/apps/files_encryption/lib/keymanager.php @@ -1,325 +1,323 @@ -<?php
-
-/**
- * ownCloud
- *
- * @author Bjoern Schiessle
- * @copyright 2012 Bjoern Schiessle <schiessle@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-namespace OCA\Encryption;
-
-/**
- * @brief Class to manage storage and retrieval of encryption keys
- * @note Where a method requires a view object, it's root must be '/'
- */
-class Keymanager {
-
- /**
- * @brief retrieve the ENCRYPTED private key from a user
- *
- * @return string private key or false
- * @note the key returned by this method must be decrypted before use
- */
- public static function getPrivateKey( \OC_FilesystemView $view, $user ) {
-
- $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key';
-
- $key = $view->file_get_contents( $path );
-
- return $key;
- }
-
- /**
- * @brief retrieve public key for a specified user
- * @return string public key or false
- */
- public static function getPublicKey( \OC_FilesystemView $view, $userId ) {
-
- return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' );
-
- }
-
- /**
- * @brief retrieve both keys from a user (private and public)
- * @return array keys: privateKey, publicKey
- */
- public static function getUserKeys( \OC_FilesystemView $view, $userId ) {
-
- return array(
- 'publicKey' => self::getPublicKey( $view, $userId )
- , 'privateKey' => self::getPrivateKey( $view, $userId )
- );
-
- }
-
- /**
- * @brief Retrieve public keys of all users with access to a file
- * @param string $path Path to file
- * @return array of public keys for the given file
- * @note Checks that the sharing app is enabled should be performed
- * by client code, that isn't checked here
- */
- public static function getPublicKeys( \OC_FilesystemView $view, $userId, $filePath ) {
-
- $path = ltrim( $path, '/' );
-
- $filepath = '/' . $userId . '/files/' . $filePath;
-
- // Check if sharing is enabled
- if ( OC_App::isEnabled( 'files_sharing' ) ) {
-
-
-
- } else {
-
- // check if it is a file owned by the user and not shared at all
- $userview = new \OC_FilesystemView( '/'.$userId.'/files/' );
-
- if ( $userview->file_exists( $path ) ) {
-
- $users[] = $userId;
-
- }
-
- }
-
- $view = new \OC_FilesystemView( '/public-keys/' );
-
- $keylist = array();
-
- $count = 0;
-
- foreach ( $users as $user ) {
-
- $keylist['key'.++$count] = $view->file_get_contents( $user.'.public.key' );
-
- }
-
- return $keylist;
-
- }
-
- /**
- * @brief store file encryption key
- *
- * @param string $path relative path of the file, including filename
- * @param string $key
- * @return bool true/false
- * @note The keyfile is not encrypted here. Client code must
- * asymmetrically encrypt the keyfile before passing it to this method
- */
- public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) {
-
- $basePath = '/' . $userId . '/files_encryption/keyfiles';
-
- $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId );
-
- if ( $view->is_dir( $basePath . '/' . $targetPath ) ) {
-
-
-
- } else {
-
- // Save the keyfile in parallel directory
- return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
-
- }
-
- }
-
- /**
- * @brief retrieve keyfile for an encrypted file
- * @param string file name
- * @return string file key or false on failure
- * @note The keyfile returned is asymmetrically encrypted. Decryption
- * of the keyfile must be performed by client code
- */
- public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) {
-
- $filePath_f = ltrim( $filePath, '/' );
-
- $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key';
-
- if ( $view->file_exists( $catfilePath ) ) {
-
- return $view->file_get_contents( $catfilePath );
-
- } else {
-
- return false;
-
- }
-
- }
-
- /**
- * @brief Delete a keyfile
- *
- * @param OC_FilesystemView $view
- * @param string $userId username
- * @param string $path path of the file the key belongs to
- * @return bool Outcome of unlink operation
- * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
- * /data/admin/files/mydoc.txt
- */
- public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) {
-
- $trimmed = ltrim( $path, '/' );
- $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key';
-
- // Unlink doesn't tell us if file was deleted (not found returns
- // true), so we perform our own test
- if ( $view->file_exists( $keyPath ) ) {
-
- return $view->unlink( $keyPath );
-
- } else {
-
- \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR );
-
- return false;
-
- }
-
- }
-
- /**
- * @brief store private key from the user
- * @param string key
- * @return bool
- * @note Encryption of the private key must be performed by client code
- * as no encryption takes place here
- */
- public static function setPrivateKey( $key ) {
-
- $user = \OCP\User::getUser();
-
- $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' );
-
- \OC_FileProxy::$enabled = false;
-
- if ( !$view->file_exists( '' ) ) $view->mkdir( '' );
-
- return $view->file_put_contents( $user . '.private.key', $key );
-
- \OC_FileProxy::$enabled = true;
-
- }
-
- /**
- * @brief store private keys from the user
- *
- * @param string privatekey
- * @param string publickey
- * @return bool true/false
- */
- public static function setUserKeys($privatekey, $publickey) {
-
- return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) );
-
- }
-
- /**
- * @brief store public key of the user
- *
- * @param string key
- * @return bool true/false
- */
- public static function setPublicKey( $key ) {
-
- $view = new \OC_FilesystemView( '/public-keys' );
-
- \OC_FileProxy::$enabled = false;
-
- if ( !$view->file_exists( '' ) ) $view->mkdir( '' );
-
- return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key );
-
- \OC_FileProxy::$enabled = true;
-
- }
-
- /**
- * @note 'shareKey' is a more user-friendly name for env_key
- */
- public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) {
-
- $basePath = '/' . $userId . '/files_encryption/share-keys';
-
- $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId );
-
- return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey );
-
- }
-
- /**
- * @brief Make preparations to vars and filesystem for saving a keyfile
- */
- public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) {
-
- $targetPath = ltrim( $path, '/' );
-
- $path_parts = pathinfo( $targetPath );
-
- // If the file resides within a subdirectory, create it
- if (
- isset( $path_parts['dirname'] )
- && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] )
- ) {
-
- $view->mkdir( $basePath . '/' . $path_parts['dirname'] );
-
- }
-
- return $targetPath;
-
- }
-
- /**
- * @brief change password of private encryption key
- *
- * @param string $oldpasswd old password
- * @param string $newpasswd new password
- * @return bool true/false
- */
- public static function changePasswd($oldpasswd, $newpasswd) {
-
- if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) {
- return Crypt::changekeypasscode($oldpasswd, $newpasswd);
- }
- return false;
-
- }
-
- /**
- * @brief Fetch the legacy encryption key from user files
- * @param string $login used to locate the legacy key
- * @param string $passphrase used to decrypt the legacy key
- * @return true / false
- *
- * if the key is left out, the default handeler will be used
- */
- public function getLegacyKey() {
-
- $user = \OCP\User::getUser();
- $view = new \OC_FilesystemView( '/' . $user );
- return $view->file_get_contents( 'encryption.key' );
-
- }
-
+<?php + +/** + * ownCloud + * + * @author Bjoern Schiessle + * @copyright 2012 Bjoern Schiessle <schiessle@owncloud.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Encryption; + +/** + * @brief Class to manage storage and retrieval of encryption keys + * @note Where a method requires a view object, it's root must be '/' + */ +class Keymanager { + + /** + * @brief retrieve the ENCRYPTED private key from a user + * + * @return string private key or false + * @note the key returned by this method must be decrypted before use + */ + public static function getPrivateKey( \OC_FilesystemView $view, $user ) { + + $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; + + $key = $view->file_get_contents( $path ); + + return $key; + } + + /** + * @brief retrieve public key for a specified user + * @param \OC_FilesystemView $view + * @param $userId + * @return string public key or false + */ + public static function getPublicKey( \OC_FilesystemView $view, $userId ) { + + return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); + + } + + /** + * @brief retrieve both keys from a user (private and public) + * @param \OC_FilesystemView $view + * @param $userId + * @return array keys: privateKey, publicKey + */ + public static function getUserKeys( \OC_FilesystemView $view, $userId ) { + + return array( + 'publicKey' => self::getPublicKey( $view, $userId ) + , 'privateKey' => self::getPrivateKey( $view, $userId ) + ); + + } + + /** + * @brief Retrieve public keys of all users with access to a file + * @param string $path Path to file + * @return array of public keys for the given file + * @note Checks that the sharing app is enabled should be performed + * by client code, that isn't checked here + */ + public static function getPublicKeys( \OC_FilesystemView $view, $userId, $filePath ) { + + $path = ltrim( $path, '/' ); + + $filepath = '/' . $userId . '/files/' . $filePath; + + // Check if sharing is enabled + if ( OC_App::isEnabled( 'files_sharing' ) ) { + + + + } else { + + // check if it is a file owned by the user and not shared at all + $userview = new \OC_FilesystemView( '/'.$userId.'/files/' ); + + if ( $userview->file_exists( $path ) ) { + + $users[] = $userId; + + } + + } + + $view = new \OC_FilesystemView( '/public-keys/' ); + + $keylist = array(); + + $count = 0; + + foreach ( $users as $user ) { + + $keylist['key'.++$count] = $view->file_get_contents( $user.'.public.key' ); + + } + + return $keylist; + + } + + /** + * @brief store file encryption key + * + * @param string $path relative path of the file, including filename + * @param string $key + * @return bool true/false + * @note The keyfile is not encrypted here. Client code must + * asymmetrically encrypt the keyfile before passing it to this method + */ + public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) { + + $basePath = '/' . $userId . '/files_encryption/keyfiles'; + + $targetPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + + if ( $view->is_dir( $basePath . '/' . $targetPath ) ) { + + + + } else { + + // Save the keyfile in parallel directory + return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile ); + + } + + } + + /** + * @brief retrieve keyfile for an encrypted file + * @param \OC_FilesystemView $view + * @param $userId + * @param $filePath + * @internal param \OCA\Encryption\file $string name + * @return string file key or false + * @note The keyfile returned is asymmetrically encrypted. Decryption + * of the keyfile must be performed by client code + */ + public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { + + $filePath_f = ltrim( $filePath, '/' ); + + $catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key'; + + if ( $view->file_exists( $catfilePath ) ) { + + return $view->file_get_contents( $catfilePath ); + + } else { + + return false; + + } + + } + + /** + * @brief Delete a keyfile + * + * @param OC_FilesystemView $view + * @param string $userId username + * @param string $path path of the file the key belongs to + * @return bool Outcome of unlink operation + * @note $path must be relative to data/user/files. e.g. mydoc.txt NOT + * /data/admin/files/mydoc.txt + */ + public static function deleteFileKey( \OC_FilesystemView $view, $userId, $path ) { + + $trimmed = ltrim( $path, '/' ); + $keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key'; + + // Unlink doesn't tell us if file was deleted (not found returns + // true), so we perform our own test + if ( $view->file_exists( $keyPath ) ) { + + return $view->unlink( $keyPath ); + + } else { + + \OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR ); + + return false; + + } + + } + + /** + * @brief store private key from the user + * @param string key + * @return bool + * @note Encryption of the private key must be performed by client code + * as no encryption takes place here + */ + public static function setPrivateKey( $key ) { + + $user = \OCP\User::getUser(); + + $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); + + \OC_FileProxy::$enabled = false; + + if ( !$view->file_exists( '' ) ) + $view->mkdir( '' ); + + return $view->file_put_contents( $user . '.private.key', $key ); + + } + + /** + * @brief store private keys from the user + * + * @param string privatekey + * @param string publickey + * @return bool true/false + */ + public static function setUserKeys($privatekey, $publickey) { + + return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) ); + + } + + /** + * @brief store public key of the user + * + * @param string key + * @return bool true/false + */ + public static function setPublicKey( $key ) { + + $view = new \OC_FilesystemView( '/public-keys' ); + + \OC_FileProxy::$enabled = false; + + if ( !$view->file_exists( '' ) ) + $view->mkdir( '' ); + + return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); + + + } + + /** + * @brief store file encryption key + * + * @param string $path relative path of the file, including filename + * @param string $key + * @param null $view + * @param string $dbClassName + * @return bool true/false + * @note The keyfile is not encrypted here. Client code must + * asymmetrically encrypt the keyfile before passing it to this method + */ + public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) { + + $basePath = '/' . $userId . '/files_encryption/share-keys'; + + $shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId ); + + return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey ); + + } + + /** + * @brief Make preparations to vars and filesystem for saving a keyfile + */ + public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) { + + $targetPath = ltrim( $path, '/' ); + + $path_parts = pathinfo( $targetPath ); + + // If the file resides within a subdirectory, create it + if ( + isset( $path_parts['dirname'] ) + && ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] ) + ) { + + $view->mkdir( $basePath . '/' . $path_parts['dirname'] ); + + } + + return $targetPath; + + } + + /** + * @brief Fetch the legacy encryption key from user files + * @param string $login used to locate the legacy key + * @param string $passphrase used to decrypt the legacy key + * @return true / false + * + * if the key is left out, the default handler will be used + */ + public function getLegacyKey() { + + $user = \OCP\User::getUser(); + $view = new \OC_FilesystemView( '/' . $user ); + return $view->file_get_contents( 'encryption.key' ); + + } + }
\ No newline at end of file diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php index d4b993b4c06..65d7d57a05a 100644 --- a/apps/files_encryption/lib/stream.php +++ b/apps/files_encryption/lib/stream.php @@ -173,7 +173,7 @@ class Stream { // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' - \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', OCP\Util::FATAL ); + \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL ); die(); @@ -209,7 +209,7 @@ class Stream { } /** - * @brief Encrypt and pad data ready for writting to disk + * @brief Encrypt and pad data ready for writing to disk * @param string $plainData data to be encrypted * @param string $key key to use for encryption * @return encrypted data on success, false on failure @@ -403,7 +403,7 @@ class Stream { $encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile ); // Write the data chunk to disk. This will be - // addended to the last data chunk if the file + // attended to the last data chunk if the file // being handled totals more than 6126 bytes fwrite( $this->handle, $encrypted ); diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php index 6fe4ea6d564..af0273cfdc4 100644 --- a/apps/files_encryption/settings-personal.php +++ b/apps/files_encryption/settings-personal.php @@ -12,8 +12,6 @@ $blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_b $tmpl->assign( 'blacklist', $blackList );
-OCP\Util::addscript('files_encryption','settings-personal');
-
return $tmpl->fetchPage();
return null;
diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php index 1f71efb1735..47467c52c08 100644 --- a/apps/files_encryption/templates/settings-personal.php +++ b/apps/files_encryption/templates/settings-personal.php @@ -16,7 +16,7 @@ <?php echo $type; ?>
</li>
<?php endforeach; ?>
- </p>
+ </ul>
<?php endif; ?>
</fieldset>
</form>
diff --git a/core/ajax/translations.php b/core/ajax/translations.php index e22cbad4708..e52a2e9b1e8 100644 --- a/core/ajax/translations.php +++ b/core/ajax/translations.php @@ -22,6 +22,7 @@ */ $app = $_POST["app"]; +$app = OC_App::cleanAppId($app); $l = OC_L10N::get( $app ); diff --git a/core/css/styles.css b/core/css/styles.css index 556ca6b82bb..e6a4bf61995 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -319,6 +319,8 @@ a.bookmarklet { background-color:#ddd; border:1px solid #ccc; padding:5px;paddin .arrow.left { left:-13px; bottom:1.2em; -webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); -o-transform:rotate(270deg); -ms-transform:rotate(270deg); transform:rotate(270deg); } .arrow.up { top:-8px; right:2em; } .arrow.down { -webkit-transform:rotate(180deg); -moz-transform:rotate(180deg); -o-transform:rotate(180deg); -ms-transform:rotate(180deg); transform:rotate(180deg); } +.help-includes {overflow: hidden; width: 100%; height: 100%; -moz-box-sizing: border-box; box-sizing: border-box; padding-top: 2.8em; } +.help-iframe {width: 100%; height: 100%; margin: 0;padding: 0; border: 0; overflow: auto;} /* ---- BREADCRUMB ---- */ div.crumb { float:left; display:block; background:url('../img/breadcrumb.svg') no-repeat right 0; padding:.75em 1.5em 0 1em; height:2.9em; } diff --git a/core/img/filetypes/application.png b/core/img/filetypes/application.png Binary files differnew file mode 100644 index 00000000000..1dee9e36609 --- /dev/null +++ b/core/img/filetypes/application.png diff --git a/core/routes.php b/core/routes.php index 7408858b107..2527816b662 100644 --- a/core/routes.php +++ b/core/routes.php @@ -6,6 +6,10 @@ * See the COPYING-README file. */ +// Post installation check +$this->create('post_setup_check', '/post-setup-check') + ->action('OC_Setup', 'postSetupCheck'); + // Core ajax actions // Search $this->create('search_ajax_search', '/search/ajax/search.php') diff --git a/core/setup.php b/core/setup.php index 66b8cf378bd..f16385466cb 100644 --- a/core/setup.php +++ b/core/setup.php @@ -43,7 +43,7 @@ if(isset($_POST['install']) AND $_POST['install']=='true') { OC_Template::printGuestPage("", "installation", $options); } else { - header("Location: ".OC::$WEBROOT.'/'); + header( 'Location: '.OC_Helper::linkToRoute( 'post_setup_check' )); exit(); } } diff --git a/db_structure.xml b/db_structure.xml index f4111bfabd0..fc7f1082ffa 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -96,6 +96,50 @@ <table> + <name>*dbprefix*file_map</name> + + <declaration> + + <field> + <name>logic_path</name> + <type>text</type> + <default></default> + <notnull>true</notnull> + <length>512</length> + </field> + + <field> + <name>physic_path</name> + <type>text</type> + <default></default> + <notnull>true</notnull> + <length>512</length> + </field> + + <index> + <name>file_map_lp_index</name> + <unique>true</unique> + <field> + <name>logic_path</name> + <sorting>ascending</sorting> + </field> + </index> + + <index> + <name>file_map_pp_index</name> + <unique>true</unique> + <field> + <name>physic_path</name> + <sorting>ascending</sorting> + </field> + </index> + + </declaration> + + </table> + + <table> + <name>*dbprefix*mimetypes</name> <declaration> diff --git a/lib/app.php b/lib/app.php index 3a4e21e8cd1..54f16d6bdcd 100644 --- a/lib/app.php +++ b/lib/app.php @@ -39,6 +39,15 @@ class OC_App{ static private $altLogin = array(); /** + * @brief clean the appid + * @param $app Appid that needs to be cleaned + * @return string + */ + public static function cleanAppId($app) { + return str_replace(array('\0', '/', '\\', '..'), '', $app); + } + + /** * @brief loads all apps * @param array $types * @return bool diff --git a/lib/base.php b/lib/base.php index 5bfdb0b7c0a..5bca1cde2d5 100644 --- a/lib/base.php +++ b/lib/base.php @@ -468,7 +468,7 @@ class OC { register_shutdown_function(array('OC_Helper', 'cleanTmp')); //parse the given parameters - self::$REQUESTEDAPP = (isset($_GET['app']) && trim($_GET['app']) != '' && !is_null($_GET['app']) ? str_replace(array('\0', '/', '\\', '..'), '', strip_tags($_GET['app'])) : OC_Config::getValue('defaultapp', 'files')); + self::$REQUESTEDAPP = (isset($_GET['app']) && trim($_GET['app']) != '' && !is_null($_GET['app']) ? OC_App::cleanAppId(strip_tags($_GET['app'])) : OC_Config::getValue('defaultapp', 'files')); if (substr_count(self::$REQUESTEDAPP, '?') != 0) { $app = substr(self::$REQUESTEDAPP, 0, strpos(self::$REQUESTEDAPP, '?')); $param = substr($_GET['app'], strpos($_GET['app'], '?') + 1); @@ -548,6 +548,7 @@ class OC { require_once 'core/setup.php'; exit(); } + $request = OC_Request::getPathInfo(); if(substr($request, -3) !== '.js'){// we need these files during the upgrade self::checkMaintenanceMode(); diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php index 8d504af6163..9a5546dce3f 100644 --- a/lib/files/cache/scanner.php +++ b/lib/files/cache/scanner.php @@ -138,7 +138,7 @@ class Scanner { * walk over any folders that are not fully scanned yet and scan them */ public function backgroundScan() { - while ($path = $this->cache->getIncomplete()) { + while (($path = $this->cache->getIncomplete()) !== false) { $this->scan($path); $this->cache->correctFolderSize($path); } diff --git a/lib/files/mapper.php b/lib/files/mapper.php new file mode 100644 index 00000000000..90e4e1ca669 --- /dev/null +++ b/lib/files/mapper.php @@ -0,0 +1,216 @@ +<?php + +namespace OC\Files; + +/** + * class Mapper is responsible to translate logical paths to physical paths and reverse + */ +class Mapper +{ + /** + * @param string $logicPath + * @param bool $create indicates if the generated physical name shall be stored in the database or not + * @return string the physical path + */ + public function logicToPhysical($logicPath, $create) { + $physicalPath = $this->resolveLogicPath($logicPath); + if ($physicalPath !== null) { + return $physicalPath; + } + + return $this->create($logicPath, $create); + } + + /** + * @param string $physicalPath + * @return string|null + */ + public function physicalToLogic($physicalPath) { + $logicPath = $this->resolvePhysicalPath($physicalPath); + if ($logicPath !== null) { + return $logicPath; + } + + $this->insert($physicalPath, $physicalPath); + return $physicalPath; + } + + /** + * @param string $path + * @param bool $isLogicPath indicates if $path is logical or physical + * @param $recursive + */ + public function removePath($path, $isLogicPath, $recursive) { + if ($recursive) { + $path=$path.'%'; + } + + if ($isLogicPath) { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?'); + $query->execute(array($path)); + } else { + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*file_map` WHERE `physic_path` LIKE ?'); + $query->execute(array($path)); + } + } + + /** + * @param $path1 + * @param $path2 + * @throws \Exception + */ + public function copy($path1, $path2) + { + $path1 = $this->stripLast($path1); + $path2 = $this->stripLast($path2); + $physicPath1 = $this->logicToPhysical($path1, true); + $physicPath2 = $this->logicToPhysical($path2, true); + + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `logic_path` LIKE ?'); + $result = $query->execute(array($path1.'%')); + $updateQuery = \OC_DB::prepare('UPDATE `*PREFIX*file_map`' + .' SET `logic_path` = ?' + .' AND `physic_path` = ?' + .' WHERE `logic_path` = ?'); + while( $row = $result->fetchRow()) { + $currentLogic = $row['logic_path']; + $currentPhysic = $row['physic_path']; + $newLogic = $path2.$this->stripRootFolder($currentLogic, $path1); + $newPhysic = $physicPath2.$this->stripRootFolder($currentPhysic, $physicPath1); + if ($path1 !== $currentLogic) { + try { + $updateQuery->execute(array($newLogic, $newPhysic, $currentLogic)); + } catch (\Exception $e) { + error_log('Mapper::Copy failed '.$currentLogic.' -> '.$newLogic.'\n'.$e); + throw $e; + } + } + } + } + + /** + * @param $path + * @param $root + * @return bool|string + */ + public function stripRootFolder($path, $root) { + if (strpos($path, $root) !== 0) { + // throw exception ??? + return false; + } + if (strlen($path) > strlen($root)) { + return substr($path, strlen($root)); + } + + return ''; + } + + private function stripLast($path) { + if (substr($path, -1) == '/') { + $path = substr_replace($path ,'',-1); + } + return $path; + } + + private function resolveLogicPath($logicPath) { + $logicPath = $this->stripLast($logicPath); + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `logic_path` = ?'); + $result = $query->execute(array($logicPath)); + $result = $result->fetchRow(); + + return $result['physic_path']; + } + + private function resolvePhysicalPath($physicalPath) { + $physicalPath = $this->stripLast($physicalPath); + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*file_map` WHERE `physic_path` = ?'); + $result = $query->execute(array($physicalPath)); + $result = $result->fetchRow(); + + return $result['logic_path']; + } + + private function create($logicPath, $store) { + $logicPath = $this->stripLast($logicPath); + $index = 0; + + // create the slugified path + $physicalPath = $this->slugifyPath($logicPath); + + // detect duplicates + while ($this->resolvePhysicalPath($physicalPath) !== null) { + $physicalPath = $this->slugifyPath($physicalPath, $index++); + } + + // insert the new path mapping if requested + if ($store) { + $this->insert($logicPath, $physicalPath); + } + + return $physicalPath; + } + + private function insert($logicPath, $physicalPath) { + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*file_map`(`logic_path`,`physic_path`) VALUES(?,?)'); + $query->execute(array($logicPath, $physicalPath)); + } + + private function slugifyPath($path, $index=null) { + $pathElements = explode('/', $path); + $sluggedElements = array(); + + // skip slugging the drive letter on windows - TODO: test if local path + if (strpos(strtolower(php_uname('s')), 'win') !== false) { + $sluggedElements[]= $pathElements[0]; + array_shift($pathElements); + } + foreach ($pathElements as $pathElement) { + // TODO: remove file ext before slugify on last element + $sluggedElements[] = self::slugify($pathElement); + } + + // + // TODO: add the index before the file extension + // + if ($index !== null) { + $last= end($sluggedElements); + array_pop($sluggedElements); + array_push($sluggedElements, $last.'-'.$index); + } + return implode(DIRECTORY_SEPARATOR, $sluggedElements); + } + + /** + * Modifies a string to remove all non ASCII characters and spaces. + * + * @param string $text + * @return string + */ + private function slugify($text) + { + // replace non letter or digits by - + $text = preg_replace('~[^\\pL\d]+~u', '-', $text); + + // trim + $text = trim($text, '-'); + + // transliterate + if (function_exists('iconv')) { + $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text); + } + + // lowercase + $text = strtolower($text); + + // remove unwanted characters + $text = preg_replace('~[^-\w]+~', '', $text); + + if (empty($text)) + { + // TODO: we better generate a guid in this case + return 'n-a'; + } + + return $text; + } +} diff --git a/lib/files/storage/local.php b/lib/files/storage/local.php index a5db4ba9194..d387a898320 100644 --- a/lib/files/storage/local.php +++ b/lib/files/storage/local.php @@ -8,6 +8,10 @@ namespace OC\Files\Storage; +if (\OC_Util::runningOnWindows()) { + require_once 'mappedlocal.php'; +} else { + /** * for local filestore, we only have to map the paths */ @@ -245,3 +249,4 @@ class Local extends \OC\Files\Storage\Common{ return $this->filemtime($path)>$time; } } +} diff --git a/lib/files/storage/mappedlocal.php b/lib/files/storage/mappedlocal.php new file mode 100644 index 00000000000..80dd79bc41f --- /dev/null +++ b/lib/files/storage/mappedlocal.php @@ -0,0 +1,335 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OC\Files\Storage; + +/** + * for local filestore, we only have to map the paths + */ +class Local extends \OC\Files\Storage\Common{ + protected $datadir; + private $mapper; + + public function __construct($arguments) { + $this->datadir=$arguments['datadir']; + if(substr($this->datadir, -1)!=='/') { + $this->datadir.='/'; + } + + $this->mapper= new \OC\Files\Mapper(); + } + public function __destruct() { + if (defined('PHPUNIT_RUN')) { + $this->mapper->removePath($this->datadir, true, true); + } + } + public function getId(){ + return 'local::'.$this->datadir; + } + public function mkdir($path) { + return @mkdir($this->buildPath($path)); + } + public function rmdir($path) { + if ($result = @rmdir($this->buildPath($path))) { + $this->cleanMapper($path); + } + return $result; + } + public function opendir($path) { + $files = array('.', '..'); + $physicalPath= $this->buildPath($path); + + $logicalPath = $this->mapper->physicalToLogic($physicalPath); + $dh = opendir($physicalPath); + while ($file = readdir($dh)) { + if ($file === '.' or $file === '..') { + continue; + } + + $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.DIRECTORY_SEPARATOR.$file); + + $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); + $file = $this->stripLeading($file); + $files[]= $file; + } + + \OC\Files\Stream\Dir::register('local-win32'.$path, $files); + return opendir('fakedir://local-win32'.$path); + } + public function is_dir($path) { + if(substr($path,-1)=='/') { + $path=substr($path, 0, -1); + } + return is_dir($this->buildPath($path)); + } + public function is_file($path) { + return is_file($this->buildPath($path)); + } + public function stat($path) { + $fullPath = $this->buildPath($path); + $statResult = stat($fullPath); + + if ($statResult['size'] < 0) { + $size = self::getFileSizeFromOS($fullPath); + $statResult['size'] = $size; + $statResult[7] = $size; + } + return $statResult; + } + public function filetype($path) { + $filetype=filetype($this->buildPath($path)); + if($filetype=='link') { + $filetype=filetype(realpath($this->buildPath($path))); + } + return $filetype; + } + public function filesize($path) { + if($this->is_dir($path)) { + return 0; + }else{ + $fullPath = $this->buildPath($path); + $fileSize = filesize($fullPath); + if ($fileSize < 0) { + return self::getFileSizeFromOS($fullPath); + } + + return $fileSize; + } + } + public function isReadable($path) { + return is_readable($this->buildPath($path)); + } + public function isUpdatable($path) { + return is_writable($this->buildPath($path)); + } + public function file_exists($path) { + return file_exists($this->buildPath($path)); + } + public function filemtime($path) { + return filemtime($this->buildPath($path)); + } + public function touch($path, $mtime=null) { + // sets the modification time of the file to the given value. + // If mtime is nil the current time is set. + // note that the access time of the file always changes to the current time. + if(!is_null($mtime)) { + $result=touch( $this->buildPath($path), $mtime ); + }else{ + $result=touch( $this->buildPath($path)); + } + if( $result ) { + clearstatcache( true, $this->buildPath($path) ); + } + + return $result; + } + public function file_get_contents($path) { + return file_get_contents($this->buildPath($path)); + } + public function file_put_contents($path, $data) {//trigger_error("$path = ".var_export($path, 1)); + return file_put_contents($this->buildPath($path), $data); + } + public function unlink($path) { + return $this->delTree($path); + } + public function rename($path1, $path2) { + if (!$this->isUpdatable($path1)) { + \OC_Log::write('core','unable to rename, file is not writable : '.$path1,\OC_Log::ERROR); + return false; + } + if(! $this->file_exists($path1)) { + \OC_Log::write('core','unable to rename, file does not exists : '.$path1,\OC_Log::ERROR); + return false; + } + + $physicPath1 = $this->buildPath($path1); + $physicPath2 = $this->buildPath($path2); + if($return=rename($physicPath1, $physicPath2)) { + // mapper needs to create copies or all children + $this->copyMapping($path1, $path2); + $this->cleanMapper($physicPath1, false, true); + } + return $return; + } + public function copy($path1, $path2) { + if($this->is_dir($path2)) { + if(!$this->file_exists($path2)) { + $this->mkdir($path2); + } + $source=substr($path1, strrpos($path1, '/')+1); + $path2.=$source; + } + if($return=copy($this->buildPath($path1), $this->buildPath($path2))) { + // mapper needs to create copies or all children + $this->copyMapping($path1, $path2); + } + return $return; + } + public function fopen($path, $mode) { + if($return=fopen($this->buildPath($path), $mode)) { + switch($mode) { + case 'r': + break; + case 'r+': + case 'w+': + case 'x+': + case 'a+': + break; + case 'w': + case 'x': + case 'a': + break; + } + } + return $return; + } + + public function getMimeType($path) { + if($this->isReadable($path)) { + return \OC_Helper::getMimeType($this->buildPath($path)); + }else{ + return false; + } + } + + private function delTree($dir, $isLogicPath=true) { + $dirRelative=$dir; + if ($isLogicPath) { + $dir=$this->buildPath($dir); + } + if (!file_exists($dir)) { + return true; + } + if (!is_dir($dir) || is_link($dir)) { + if($return=unlink($dir)) { + $this->cleanMapper($dir, false); + return $return; + } + } + foreach (scandir($dir) as $item) { + if ($item == '.' || $item == '..') { + continue; + } + if(is_file($dir.'/'.$item)) { + if(unlink($dir.'/'.$item)) { + $this->cleanMapper($dir.'/'.$item, false); + } + }elseif(is_dir($dir.'/'.$item)) { + if (!$this->delTree($dir. "/" . $item, false)) { + return false; + }; + } + } + if($return=rmdir($dir)) { + $this->cleanMapper($dir, false); + } + return $return; + } + + private static function getFileSizeFromOS($fullPath) { + $name = strtolower(php_uname('s')); + // Windows OS: we use COM to access the filesystem + if (strpos($name, 'win') !== false) { + if (class_exists('COM')) { + $fsobj = new \COM("Scripting.FileSystemObject"); + $f = $fsobj->GetFile($fullPath); + return $f->Size; + } + } else if (strpos($name, 'bsd') !== false) { + if (\OC_Helper::is_function_enabled('exec')) { + return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); + } + } else if (strpos($name, 'linux') !== false) { + if (\OC_Helper::is_function_enabled('exec')) { + return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); + } + } else { + \OC_Log::write('core', 'Unable to determine file size of "'.$fullPath.'". Unknown OS: '.$name, \OC_Log::ERROR); + } + + return 0; + } + + public function hash($path, $type, $raw=false) { + return hash_file($type, $this->buildPath($path), $raw); + } + + public function free_space($path) { + return @disk_free_space($this->buildPath($path)); + } + + public function search($query) { + return $this->searchInDir($query); + } + public function getLocalFile($path) { + return $this->buildPath($path); + } + public function getLocalFolder($path) { + return $this->buildPath($path); + } + + protected function searchInDir($query, $dir='', $isLogicPath=true) { + $files=array(); + $physicalDir = $this->buildPath($dir); + foreach (scandir($physicalDir) as $item) { + if ($item == '.' || $item == '..') + continue; + $physicalItem = $this->mapper->physicalToLogic($physicalDir.DIRECTORY_SEPARATOR.$item); + $item = substr($physicalItem, strlen($physicalDir)+1); + + if(strstr(strtolower($item), strtolower($query)) !== false) { + $files[]=$dir.'/'.$item; + } + if(is_dir($physicalItem)) { + $files=array_merge($files, $this->searchInDir($query, $physicalItem, false)); + } + } + return $files; + } + + /** + * check if a file or folder has been updated since $time + * @param string $path + * @param int $time + * @return bool + */ + public function hasUpdated($path, $time) { + return $this->filemtime($path)>$time; + } + + private function buildPath($path, $create=true) { + $path = $this->stripLeading($path); + $fullPath = $this->datadir.$path; + return $this->mapper->logicToPhysical($fullPath, $create); + } + + private function cleanMapper($path, $isLogicPath=true, $recursive=true) { + $fullPath = $path; + if ($isLogicPath) { + $fullPath = $this->datadir.$path; + } + $this->mapper->removePath($fullPath, $isLogicPath, $recursive); + } + + private function copyMapping($path1, $path2) { + $path1 = $this->stripLeading($path1); + $path2 = $this->stripLeading($path2); + + $fullPath1 = $this->datadir.$path1; + $fullPath2 = $this->datadir.$path2; + + $this->mapper->copy($fullPath1, $fullPath2); + } + + private function stripLeading($path) { + if(strpos($path, '/') === 0) { + $path = substr($path, 1); + } + + return $path; + } +} diff --git a/lib/files/view.php b/lib/files/view.php index dfcb770328b..1a234228eab 100644 --- a/lib/files/view.php +++ b/lib/files/view.php @@ -509,11 +509,7 @@ class View { if (Filesystem::isValidPath($path)) { $source = $this->fopen($path, 'r'); if ($source) { - $extension = ''; - $extOffset = strpos($path, '.'); - if ($extOffset !== false) { - $extension = substr($path, strrpos($path, '.')); - } + $extension = pathinfo($path, PATHINFO_EXTENSION); $tmpFile = \OC_Helper::tmpFile($extension); file_put_contents($tmpFile, $source); return $tmpFile; diff --git a/lib/l10n.php b/lib/l10n.php index ee879009265..e272bcd79f3 100644 --- a/lib/l10n.php +++ b/lib/l10n.php @@ -97,7 +97,7 @@ class OC_L10N{ if ($this->app === true) { return; } - $app = $this->app; + $app = OC_App::cleanAppId($this->app); $lang = $this->lang; $this->app = true; // Find the right language diff --git a/lib/mimetypes.list.php b/lib/mimetypes.list.php index fc87d011ecd..86ce9c6c237 100644 --- a/lib/mimetypes.list.php +++ b/lib/mimetypes.list.php @@ -97,4 +97,6 @@ return array( 'ai' => 'application/illustrator', 'epub' => 'application/epub+zip', 'mobi' => 'application/x-mobipocket-ebook', + 'exe' => 'application', + 'msi' => 'application' ); diff --git a/lib/setup.php b/lib/setup.php index 4dd190b99fb..f342142c957 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -610,4 +610,24 @@ class OC_Setup { file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content); file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/index.html', ''); } + + /** + * @brief Post installation checks + */ + public static function postSetupCheck($params) { + // setup was successful -> webdav testing now + if (OC_Util::isWebDAVWorking()) { + header("Location: ".OC::$WEBROOT.'/'); + } else { + $l=OC_L10N::get('lib'); + + $error = $l->t('Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken.'); + $hint = $l->t('Please double check the <a href=\'%s\'>installation guides</a>.', 'http://doc.owncloud.org/server/5.0/admin_manual/installation.html'); + + $tmpl = new OC_Template('', 'error', 'guest'); + $tmpl->assign('errors', array(1 => array('error' => $error, 'hint' => $hint)), false); + $tmpl->printPage(); + exit(); + } + } } diff --git a/lib/util.php b/lib/util.php index 9ce974619bc..49d914e5fbd 100755 --- a/lib/util.php +++ b/lib/util.php @@ -516,6 +516,40 @@ class OC_Util { } } + /** + * we test if webDAV is working properly + * + * The basic assumption is that if the server returns 401/Not Authenticated for an unauthenticated PROPFIND + * the web server it self is setup properly. + * + * Why not an authenticated PROFIND and other verbs? + * - We don't have the password available + * - We have no idea about other auth methods implemented (e.g. OAuth with Bearer header) + * + */ + public static function isWebDAVWorking() { + if (!function_exists('curl_init')) { + return; + } + + $settings = array( + 'baseUri' => OC_Helper::linkToRemote('webdav'), + ); + + $client = new \Sabre_DAV_Client($settings); + + $return = true; + try { + // test PROPFIND + $client->propfind('', array('{DAV:}resourcetype')); + } catch(\Sabre_DAV_Exception_NotAuthenticated $e) { + $return = true; + } catch(\Exception $e) { + $return = false; + } + + return $return; + } /** * Check if the setlocal call doesn't work. This can happen if the right local packages are not available on the server. diff --git a/settings/admin.php b/settings/admin.php index 7cca7165153..c7848803095 100755 --- a/settings/admin.php +++ b/settings/admin.php @@ -31,6 +31,7 @@ $tmpl->assign('entriesremain', $entriesremain); $tmpl->assign('htaccessworking', $htaccessworking); $tmpl->assign('internetconnectionworking', OC_Util::isinternetconnectionworking()); $tmpl->assign('islocaleworking', OC_Util::issetlocaleworking()); +$tmpl->assign('isWebDavWorking', OC_Util::isWebDAVWorking()); $tmpl->assign('has_fileinfo', OC_Util::fileInfoLoaded()); $tmpl->assign('backgroundjobs_mode', OC_Appconfig::getValue('core', 'backgroundjobs_mode', 'ajax')); $tmpl->assign('shareAPIEnabled', OC_Appconfig::getValue('core', 'shareapi_enabled', 'yes')); diff --git a/settings/ajax/disableapp.php b/settings/ajax/disableapp.php index e89de928eac..466a719157d 100644 --- a/settings/ajax/disableapp.php +++ b/settings/ajax/disableapp.php @@ -2,6 +2,6 @@ OC_JSON::checkAdminUser(); OCP\JSON::callCheck(); -OC_App::disable($_POST['appid']); +OC_App::disable(OC_App::cleanAppId($_POST['appid'])); OC_JSON::success(); diff --git a/settings/ajax/enableapp.php b/settings/ajax/enableapp.php index 18202dc39e9..ab84aee5166 100644 --- a/settings/ajax/enableapp.php +++ b/settings/ajax/enableapp.php @@ -3,7 +3,7 @@ OC_JSON::checkAdminUser(); OCP\JSON::callCheck(); -$appid = OC_App::enable($_POST['appid']); +$appid = OC_App::enable(OC_App::cleanAppId($_POST['appid'])); if($appid !== false) { OC_JSON::success(array('data' => array('appid' => $appid))); } else { diff --git a/settings/ajax/navigationdetect.php b/settings/ajax/navigationdetect.php index 93acb50dc20..607c0e873f9 100644 --- a/settings/ajax/navigationdetect.php +++ b/settings/ajax/navigationdetect.php @@ -4,6 +4,7 @@ OC_Util::checkAdminUser(); OCP\JSON::callCheck(); $app = $_GET['app']; +$app = OC_App::cleanAppId($app); //load the one app and see what it adds to the navigation OC_App::loadApp($app); diff --git a/settings/ajax/updateapp.php b/settings/ajax/updateapp.php index 77c0bbc3e36..9367a3b5a3b 100644 --- a/settings/ajax/updateapp.php +++ b/settings/ajax/updateapp.php @@ -4,6 +4,7 @@ OC_JSON::checkAdminUser(); OCP\JSON::callCheck(); $appid = $_POST['appid']; +$appid = OC_App::cleanAppId($appid); $result = OC_Installer::updateApp($appid); if($result !== false) { diff --git a/settings/js/apps-custom.php b/settings/js/apps-custom.php index 9ec2a758ee3..d827dfc7058 100644 --- a/settings/js/apps-custom.php +++ b/settings/js/apps-custom.php @@ -23,4 +23,4 @@ foreach($combinedApps as $app) { echo("\n"); } -echo ("var appid =\"".$_GET['appid']."\";");
\ No newline at end of file +echo ("var appid =".json_encode($_GET['appid']).";");
\ No newline at end of file diff --git a/settings/templates/admin.php b/settings/templates/admin.php index 9a9a691dcbf..fac8a689883 100644 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -22,6 +22,21 @@ if (!$_['htaccessworking']) { <?php } +// is WebDAV working ? +if (!$_['isWebDavWorking']) { + ?> +<fieldset class="personalblock"> + <legend><strong><?php echo $l->t('Setup Warning');?></strong></legend> + + <span class="securitywarning"> + <?php echo $l->t('Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken.'); ?> + <?php echo $l->t('Please double check the <a href=\'%s\'>installation guides</a>.', 'http://doc.owncloud.org/server/5.0/admin_manual/installation.html'); ?> + </span> + +</fieldset> +<?php +} + // if module fileinfo available? if (!$_['has_fileinfo']) { ?> @@ -36,6 +51,7 @@ if (!$_['has_fileinfo']) { <?php } +// is locale working ? if (!$_['islocaleworking']) { ?> <fieldset class="personalblock"> diff --git a/settings/templates/help.php b/settings/templates/help.php index 7383fdcf56a..315cbfdb9a2 100644 --- a/settings/templates/help.php +++ b/settings/templates/help.php @@ -10,5 +10,6 @@ <?php } ?> <a class="button newquestion" href="http://owncloud.com" target="_blank"><?php echo $l->t( 'Commercial Support' ); ?></a> </div> -<br /><br /> -<iframe src="<?php echo($_['url']); ?>" width="100%" id="ifm" ></iframe>
\ No newline at end of file +<div class="help-includes"> + <iframe src="<?php echo($_['url']); ?>" class="help-iframe">abc</iframe> +</div> diff --git a/tests/lib/files/storage/storage.php b/tests/lib/files/storage/storage.php index 781c0f92c92..c74a16f509f 100644 --- a/tests/lib/files/storage/storage.php +++ b/tests/lib/files/storage/storage.php @@ -146,10 +146,19 @@ abstract class Storage extends \PHPUnit_Framework_TestCase { $localFolder = $this->instance->getLocalFolder('/folder'); $this->assertTrue(is_dir($localFolder)); - $this->assertTrue(file_exists($localFolder . '/lorem.txt')); - $this->assertEquals(file_get_contents($localFolder . '/lorem.txt'), file_get_contents($textFile)); - $this->assertEquals(file_get_contents($localFolder . '/bar.txt'), 'asd'); - $this->assertEquals(file_get_contents($localFolder . '/recursive/file.txt'), 'foo'); + + // test below require to use instance->getLocalFile because the physical storage might be different + $localFile = $this->instance->getLocalFile('/folder/lorem.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), file_get_contents($textFile)); + + $localFile = $this->instance->getLocalFile('/folder/bar.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), 'asd'); + + $localFile = $this->instance->getLocalFile('/folder/recursive/file.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), 'foo'); } public function testStat() { |