Merge master...
This commit is contained in:
commit
c8bbbb48d3
207 changed files with 8277 additions and 1892 deletions
|
@ -29,6 +29,7 @@
|
|||
"'.' is an invalid file name." => "'.' és un nom no vàlid per un fitxer.",
|
||||
"File name cannot be empty." => "El nom del fitxer no pot ser buit.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "El nóm no és vàlid, '\\', '/', '<', '>', ':', '\"', '|', '?' i '*' no estan permesos.",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "S'està preparant la baixada. Pot trigar una estona si els fitxers són grans.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "No es pot pujar el fitxer perquè és una carpeta o té 0 bytes",
|
||||
"Upload Error" => "Error en la pujada",
|
||||
"Close" => "Tanca",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"'.' is an invalid file name." => "'.' είναι μη έγκυρο όνομα αρχείου.",
|
||||
"File name cannot be empty." => "Το όνομα αρχείου δεν πρέπει να είναι κενό.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Μη έγκυρο όνομα, '\\', '/', '<', '>', ':', '\"', '|', '?' και '*' δεν επιτρέπονται.",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "Η λήψη προετοιμάζεται. Αυτό μπορεί να πάρει ώρα εάν τα αρχεία έχουν μεγάλο μέγεθος.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "Αδυναμία στην αποστολή του αρχείου σας αφού είναι φάκελος ή έχει 0 bytes",
|
||||
"Upload Error" => "Σφάλμα Αποστολής",
|
||||
"Close" => "Κλείσιμο",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"Missing a temporary folder" => "یک پوشه موقت گم شده است",
|
||||
"Failed to write to disk" => "نوشتن بر روی دیسک سخت ناموفق بود",
|
||||
"Files" => "فایل ها",
|
||||
"Unshare" => "لغو اشتراک",
|
||||
"Delete" => "پاک کردن",
|
||||
"Rename" => "تغییرنام",
|
||||
"replace" => "جایگزین",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"'.' is an invalid file name." => "'.' は無効なファイル名です。",
|
||||
"File name cannot be empty." => "ファイル名を空にすることはできません。",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "無効な名前、'\\', '/', '<', '>', ':', '\"', '|', '?', '*' は使用できません。",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "ダウンロードの準備中です。ファイルサイズが大きい場合は少し時間がかかるかもしれません。",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "ディレクトリもしくは0バイトのファイルはアップロードできません",
|
||||
"Upload Error" => "アップロードエラー",
|
||||
"Close" => "閉じる",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"'.' is an invalid file name." => "'.' não é um nome de ficheiro válido!",
|
||||
"File name cannot be empty." => "O nome do ficheiro não pode estar vazio.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nome Inválido, os caracteres '\\', '/', '<', '>', ':', '\"', '|', '?' e '*' não são permitidos.",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "O seu download está a ser preparado. Este processo pode demorar algum tempo se os ficheiros forem grandes.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "Não é possível fazer o envio do ficheiro devido a ser uma pasta ou ter 0 bytes",
|
||||
"Upload Error" => "Erro no envio",
|
||||
"Close" => "Fechar",
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Upload" => "Ladda upp",
|
||||
"Could not move %s - File with this name already exists" => "Kunde inte flytta %s - Det finns redan en fil med detta namn",
|
||||
"Could not move %s" => "Kan inte flytta %s",
|
||||
"Unable to rename file" => "Kan inte byta namn på filen",
|
||||
"No file was uploaded. Unknown error" => "Ingen fil uppladdad. Okänt fel",
|
||||
"There is no error, the file uploaded with success" => "Inga fel uppstod. Filen laddades upp utan problem",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Den uppladdade filen överskrider upload_max_filesize direktivet php.ini:",
|
||||
|
@ -26,6 +29,7 @@
|
|||
"'.' is an invalid file name." => "'.' är ett ogiltigt filnamn.",
|
||||
"File name cannot be empty." => "Filnamn kan inte vara tomt.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ogiltigt namn, '\\', '/', '<', '>', ':', '\"', '|', '?' och '*' är inte tillåtet.",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "Din nedladdning förbereds. Det kan ta tid om det är stora filer.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "Kunde inte ladda upp dina filer eftersom det antingen är en mapp eller har 0 bytes.",
|
||||
"Upload Error" => "Uppladdningsfel",
|
||||
"Close" => "Stäng",
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Upload" => "อัพโหลด",
|
||||
"Could not move %s - File with this name already exists" => "ไม่สามารถย้าย %s ได้ - ไฟล์ที่ใช้ชื่อนี้มีอยู่แล้ว",
|
||||
"Could not move %s" => "ไม่สามารถย้าย %s ได้",
|
||||
"Unable to rename file" => "ไม่สามารถเปลี่ยนชื่อไฟล์ได้",
|
||||
"No file was uploaded. Unknown error" => "ยังไม่มีไฟล์ใดที่ถูกอัพโหลด เกิดข้อผิดพลาดที่ไม่ทราบสาเหตุ",
|
||||
"There is no error, the file uploaded with success" => "ไม่มีข้อผิดพลาดใดๆ ไฟล์ถูกอัพโหลดเรียบร้อยแล้ว",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "ขนาดไฟล์ที่อัพโหลดมีขนาดเกิน upload_max_filesize ที่ระบุไว้ใน php.ini",
|
||||
|
@ -8,6 +11,8 @@
|
|||
"No file was uploaded" => "ยังไม่มีไฟล์ที่ถูกอัพโหลด",
|
||||
"Missing a temporary folder" => "แฟ้มเอกสารชั่วคราวเกิดการสูญหาย",
|
||||
"Failed to write to disk" => "เขียนข้อมูลลงแผ่นดิสก์ล้มเหลว",
|
||||
"Not enough space available" => "มีพื้นที่เหลือไม่เพียงพอ",
|
||||
"Invalid directory." => "ไดเร็กทอรี่ไม่ถูกต้อง",
|
||||
"Files" => "ไฟล์",
|
||||
"Unshare" => "ยกเลิกการแชร์ข้อมูล",
|
||||
"Delete" => "ลบ",
|
||||
|
@ -21,7 +26,10 @@
|
|||
"replaced {new_name} with {old_name}" => "แทนที่ {new_name} ด้วย {old_name} แล้ว",
|
||||
"unshared {files}" => "ยกเลิกการแชร์แล้ว {files} ไฟล์",
|
||||
"deleted {files}" => "ลบไฟล์แล้ว {files} ไฟล์",
|
||||
"'.' is an invalid file name." => "'.' เป็นชื่อไฟล์ที่ไม่ถูกต้อง",
|
||||
"File name cannot be empty." => "ชื่อไฟล์ไม่สามารถเว้นว่างได้",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "ชื่อที่ใช้ไม่ถูกต้อง, '\\', '/', '<', '>', ':', '\"', '|', '?' และ '*' ไม่ได้รับอนุญาตให้ใช้งานได้",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "กำลังเตรียมดาวน์โหลดข้อมูล หากไฟล์มีขนาดใหญ่ อาจใช้เวลาสักครู่",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "ไม่สามารถอัพโหลดไฟล์ของคุณได้ เนื่องจากไฟล์ดังกล่าวเป็นไดเร็กทอรี่หรือมีขนาด 0 ไบต์",
|
||||
"Upload Error" => "เกิดข้อผิดพลาดในการอัพโหลด",
|
||||
"Close" => "ปิด",
|
||||
|
@ -31,6 +39,7 @@
|
|||
"Upload cancelled." => "การอัพโหลดถูกยกเลิก",
|
||||
"File upload is in progress. Leaving the page now will cancel the upload." => "การอัพโหลดไฟล์กำลังอยู่ในระหว่างดำเนินการ การออกจากหน้าเว็บนี้จะทำให้การอัพโหลดถูกยกเลิก",
|
||||
"URL cannot be empty." => "URL ไม่สามารถเว้นว่างได้",
|
||||
"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "ชื่อโฟลเดอร์ไม่ถูกต้อง การใช้งาน 'แชร์' สงวนไว้สำหรับ Owncloud เท่านั้น",
|
||||
"{count} files scanned" => "สแกนไฟล์แล้ว {count} ไฟล์",
|
||||
"error while scanning" => "พบข้อผิดพลาดในระหว่างการสแกนไฟล์",
|
||||
"Name" => "ชื่อ",
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Upload" => "Yükle",
|
||||
"Could not move %s - File with this name already exists" => "%s taşınamadı. Bu isimde dosya zaten var.",
|
||||
"Could not move %s" => "%s taşınamadı",
|
||||
"Unable to rename file" => "Dosya adı değiştirilemedi",
|
||||
"No file was uploaded. Unknown error" => "Dosya yüklenmedi. Bilinmeyen hata",
|
||||
"There is no error, the file uploaded with success" => "Bir hata yok, dosya başarıyla yüklendi",
|
||||
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "php.ini dosyasında upload_max_filesize ile belirtilen dosya yükleme sınırı aşıldı.",
|
||||
|
@ -8,6 +11,8 @@
|
|||
"No file was uploaded" => "Hiç dosya yüklenmedi",
|
||||
"Missing a temporary folder" => "Geçici bir klasör eksik",
|
||||
"Failed to write to disk" => "Diske yazılamadı",
|
||||
"Not enough space available" => "Yeterli disk alanı yok",
|
||||
"Invalid directory." => "Geçersiz dizin.",
|
||||
"Files" => "Dosyalar",
|
||||
"Unshare" => "Paylaşılmayan",
|
||||
"Delete" => "Sil",
|
||||
|
@ -21,7 +26,10 @@
|
|||
"replaced {new_name} with {old_name}" => "{new_name} ismi {old_name} ile değiştirildi",
|
||||
"unshared {files}" => "paylaşılmamış {files}",
|
||||
"deleted {files}" => "silinen {files}",
|
||||
"'.' is an invalid file name." => "'.' geçersiz dosya adı.",
|
||||
"File name cannot be empty." => "Dosya adı boş olamaz.",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Geçersiz isim, '\\', '/', '<', '>', ':', '\"', '|', '?' ve '*' karakterlerine izin verilmemektedir.",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "İndirmeniz hazırlanıyor. Dosya büyük ise biraz zaman alabilir.",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "Dosyanızın boyutu 0 byte olduğundan veya bir dizin olduğundan yüklenemedi",
|
||||
"Upload Error" => "Yükleme hatası",
|
||||
"Close" => "Kapat",
|
||||
|
@ -31,6 +39,7 @@
|
|||
"Upload cancelled." => "Yükleme iptal edildi.",
|
||||
"File upload is in progress. Leaving the page now will cancel the upload." => "Dosya yükleme işlemi sürüyor. Şimdi sayfadan ayrılırsanız işleminiz iptal olur.",
|
||||
"URL cannot be empty." => "URL boş olamaz.",
|
||||
"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Geçersiz dizin adı. Shared isminin kullanımı Owncloud tarafından rezerver edilmiştir.",
|
||||
"{count} files scanned" => "{count} dosya tarandı",
|
||||
"error while scanning" => "tararamada hata oluşdu",
|
||||
"Name" => "Ad",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"'.' is an invalid file name." => "'.' 是一个无效的文件名。",
|
||||
"File name cannot be empty." => "文件名不能为空。",
|
||||
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "无效名称,'\\', '/', '<', '>', ':', '\"', '|', '?' 和 '*' 不被允许使用。",
|
||||
"Your download is being prepared. This might take some time if the files are big." => "下载正在准备中。如果文件较大可能会花费一些时间。",
|
||||
"Unable to upload your file as it is a directory or has 0 bytes" => "无法上传文件,因为它是一个目录或者大小为 0 字节",
|
||||
"Upload Error" => "上传错误",
|
||||
"Close" => "关闭",
|
||||
|
|
38
apps/files_encryption/ajax/mode.php
Normal file
38
apps/files_encryption/ajax/mode.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?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();
|
||||
}
|
|
@ -1,21 +1,37 @@
|
|||
<?php
|
||||
|
||||
OC::$CLASSPATH['OC_Crypt'] = 'apps/files_encryption/lib/crypt.php';
|
||||
OC::$CLASSPATH['OC_CryptStream'] = 'apps/files_encryption/lib/cryptstream.php';
|
||||
OC::$CLASSPATH['OC_FileProxy_Encryption'] = 'apps/files_encryption/lib/proxy.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Crypt'] = 'apps/files_encryption/lib/crypt.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Hooks'] = 'apps/files_encryption/hooks/hooks.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Util'] = 'apps/files_encryption/lib/util.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Keymanager'] = 'apps/files_encryption/lib/keymanager.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Stream'] = 'apps/files_encryption/lib/stream.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Proxy'] = 'apps/files_encryption/lib/proxy.php';
|
||||
OC::$CLASSPATH['OCA\Encryption\Session'] = 'apps/files_encryption/lib/session.php';
|
||||
|
||||
OC_FileProxy::register(new OC_FileProxy_Encryption());
|
||||
OC_FileProxy::register( new OCA\Encryption\Proxy() );
|
||||
|
||||
OCP\Util::connectHook('OC_User', 'post_login', 'OC_Crypt', 'loginListener');
|
||||
OCP\Util::connectHook( 'OC_User','post_login', 'OCA\Encryption\Hooks', 'login' );
|
||||
OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' );
|
||||
OCP\Util::connectHook( 'OC_User','post_setPassword','OCA\Encryption\Hooks' ,'setPassphrase' );
|
||||
|
||||
stream_wrapper_register('crypt', 'OC_CryptStream');
|
||||
stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' );
|
||||
|
||||
// force the user to re-loggin if the encryption key isn't unlocked
|
||||
// (happens when a user is logged in before the encryption app is enabled)
|
||||
if ( ! isset($_SESSION['enckey']) and OCP\User::isLoggedIn()) {
|
||||
$session = new OCA\Encryption\Session();
|
||||
|
||||
if (
|
||||
! $session->getPrivateKey( \OCP\USER::getUser() )
|
||||
&& OCP\User::isLoggedIn()
|
||||
&& OCA\Encryption\Crypt::mode() == 'server'
|
||||
) {
|
||||
|
||||
// Force the user to re-log in if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled)
|
||||
OCP\User::logout();
|
||||
header("Location: ".OC::$WEBROOT.'/');
|
||||
|
||||
header( "Location: " . OC::$WEBROOT.'/' );
|
||||
|
||||
exit();
|
||||
|
||||
}
|
||||
|
||||
OCP\App::registerAdmin('files_encryption', 'settings');
|
||||
OCP\App::registerAdmin( 'files_encryption', 'settings');
|
||||
OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );
|
24
apps/files_encryption/appinfo/database.xml
Normal file
24
apps/files_encryption/appinfo/database.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<database>
|
||||
<name>*dbname*</name>
|
||||
<create>true</create>
|
||||
<overwrite>false</overwrite>
|
||||
<charset>utf8</charset>
|
||||
<table>
|
||||
<name>*dbprefix*encryption</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>uid</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>mode</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
</declaration>
|
||||
</table>
|
||||
</database>
|
|
@ -2,10 +2,10 @@
|
|||
<info>
|
||||
<id>files_encryption</id>
|
||||
<name>Encryption</name>
|
||||
<description>Server side encryption of files. DEPRECATED. This app is no longer supported and will be replaced with an improved version in ownCloud 5. Only enable this features if you want to read old encrypted data. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP.</description>
|
||||
<description>Server side encryption of files. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP.</description>
|
||||
<licence>AGPL</licence>
|
||||
<author>Robin Appelman</author>
|
||||
<require>4.9</require>
|
||||
<author>Sam Tuke</author>
|
||||
<require>4</require>
|
||||
<shipped>true</shipped>
|
||||
<types>
|
||||
<filesystem/>
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.2
|
||||
0.2.1
|
143
apps/files_encryption/hooks/hooks.php
Normal file
143
apps/files_encryption/hooks/hooks.php
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke
|
||||
* @copyright 2012 Sam Tuke samtuke@owncloud.org
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Class for hook specific logic
|
||||
*/
|
||||
|
||||
class Hooks {
|
||||
|
||||
# TODO: use passphrase for encrypting private key that is separate to the login password
|
||||
|
||||
/**
|
||||
* @brief Startup encryption backend upon user login
|
||||
* @note This method should never be called for users using client side encryption
|
||||
*/
|
||||
public static function login( $params ) {
|
||||
|
||||
// if ( Crypt::mode( $params['uid'] ) == 'server' ) {
|
||||
|
||||
# TODO: use lots of dependency injection here
|
||||
|
||||
$view = new \OC_FilesystemView( '/' );
|
||||
|
||||
$util = new Util( $view, $params['uid'] );
|
||||
|
||||
if ( ! $util->ready() ) {
|
||||
|
||||
\OC_Log::write( 'Encryption library', 'User account "' . $params['uid'] . '" is not ready for encryption; configuration started' , \OC_Log::DEBUG );
|
||||
|
||||
return $util->setupServerSide( $params['password'] );
|
||||
|
||||
}
|
||||
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$encryptedKey = Keymanager::getPrivateKey( $view, $params['uid'] );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
# TODO: dont manually encrypt the private keyfile - use the config options of openssl_pkey_export instead for better mobile compatibility
|
||||
|
||||
$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] );
|
||||
|
||||
$session = new Session();
|
||||
|
||||
$session->setPrivateKey( $privateKey, $params['uid'] );
|
||||
|
||||
$view1 = new \OC_FilesystemView( '/' . $params['uid'] );
|
||||
|
||||
// Set legacy encryption key if it exists, to support
|
||||
// depreciated encryption system
|
||||
if (
|
||||
$view1->file_exists( 'encryption.key' )
|
||||
&& $legacyKey = $view1->file_get_contents( 'encryption.key' )
|
||||
) {
|
||||
|
||||
$_SESSION['legacyenckey'] = Crypt::legacyDecrypt( $legacyKey, $params['password'] );
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Change a user's encryption passphrase
|
||||
* @param array $params keys: uid, password
|
||||
*/
|
||||
public static function setPassphrase( $params ) {
|
||||
|
||||
// Only attempt to change passphrase if server-side encryption
|
||||
// is in use (client-side encryption does not have access to
|
||||
// the necessary keys)
|
||||
if ( Crypt::mode() == 'server' ) {
|
||||
|
||||
// Get existing decrypted private key
|
||||
$privateKey = $_SESSION['privateKey'];
|
||||
|
||||
// Encrypt private key with new user pwd as passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] );
|
||||
|
||||
// Save private key
|
||||
Keymanager::setPrivateKey( $encryptedPrivateKey );
|
||||
|
||||
# NOTE: Session does not need to be updated as the
|
||||
# private key has not changed, only the passphrase
|
||||
# used to decrypt it has changed
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief update the encryption key of the file uploaded by the client
|
||||
*/
|
||||
public static function updateKeyfile( $params ) {
|
||||
|
||||
if ( Crypt::mode() == 'client' ) {
|
||||
|
||||
if ( isset( $params['properties']['key'] ) ) {
|
||||
|
||||
Keymanager::setFileKey( $params['path'], $params['properties']['key'] );
|
||||
|
||||
} else {
|
||||
|
||||
\OC_Log::write(
|
||||
'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!"
|
||||
, \OC_Log::ERROR
|
||||
);
|
||||
|
||||
error_log( "Client side encryption is enabled but the client doesn't provide an encryption key for the file!" );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
38
apps/files_encryption/js/settings-personal.js
Normal file
38
apps/files_encryption/js/settings-personal.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 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' });
|
||||
}
|
||||
})
|
||||
})
|
|
@ -11,14 +11,36 @@ $(document).ready(function(){
|
|||
onuncheck:blackListChange,
|
||||
createText:'...',
|
||||
});
|
||||
|
||||
|
||||
function blackListChange(){
|
||||
var blackList=$('#encryption_blacklist').val().join(',');
|
||||
OC.AppConfig.setValue('files_encryption','type_blacklist',blackList);
|
||||
}
|
||||
|
||||
$('#enable_encryption').change(function(){
|
||||
var checked=$('#enable_encryption').is(':checked');
|
||||
OC.AppConfig.setValue('files_encryption','enable_encryption',(checked)?'true':'false');
|
||||
});
|
||||
});
|
||||
//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;
|
||||
}
|
||||
})
|
||||
})
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "التشفير",
|
||||
"Exclude the following file types from encryption" => "استبعد أنواع الملفات التالية من التشفير",
|
||||
"None" => "لا شيء",
|
||||
"Enable Encryption" => "تفعيل التشفير"
|
||||
"None" => "لا شيء"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Криптиране",
|
||||
"Enable Encryption" => "Включване на криптирането",
|
||||
"None" => "Няма",
|
||||
"Exclude the following file types from encryption" => "Изключване на следните файлови типове от криптирането"
|
||||
"Exclude the following file types from encryption" => "Изключване на следните файлови типове от криптирането",
|
||||
"None" => "Няма"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "সংকেতায়ন",
|
||||
"Enable Encryption" => "সংকেতায়ন সক্রিয় কর",
|
||||
"None" => "কোনটিই নয়",
|
||||
"Exclude the following file types from encryption" => "সংকেতায়ন থেকে নিম্নোক্ত ধরণসমূহ বাদ দাও"
|
||||
"Exclude the following file types from encryption" => "সংকেতায়ন থেকে নিম্নোক্ত ধরণসমূহ বাদ দাও",
|
||||
"None" => "কোনটিই নয়"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Encriptatge",
|
||||
"Exclude the following file types from encryption" => "Exclou els tipus de fitxers següents de l'encriptatge",
|
||||
"None" => "Cap",
|
||||
"Enable Encryption" => "Activa l'encriptatge"
|
||||
"None" => "Cap"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Šifrování",
|
||||
"Exclude the following file types from encryption" => "Při šifrování vynechat následující typy souborů",
|
||||
"None" => "Žádné",
|
||||
"Enable Encryption" => "Povolit šifrování"
|
||||
"None" => "Žádné"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Kryptering",
|
||||
"Exclude the following file types from encryption" => "Ekskluder følgende filtyper fra kryptering",
|
||||
"None" => "Ingen",
|
||||
"Enable Encryption" => "Aktivér kryptering"
|
||||
"None" => "Ingen"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Verschlüsselung",
|
||||
"Exclude the following file types from encryption" => "Die folgenden Dateitypen von der Verschlüsselung ausnehmen",
|
||||
"None" => "Keine",
|
||||
"Enable Encryption" => "Verschlüsselung aktivieren"
|
||||
"None" => "Keine"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Verschlüsselung",
|
||||
"Exclude the following file types from encryption" => "Die folgenden Dateitypen von der Verschlüsselung ausnehmen",
|
||||
"None" => "Keine",
|
||||
"Enable Encryption" => "Verschlüsselung aktivieren"
|
||||
"None" => "Keine"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Κρυπτογράφηση",
|
||||
"Exclude the following file types from encryption" => "Εξαίρεση των παρακάτω τύπων αρχείων από την κρυπτογράφηση",
|
||||
"None" => "Καμία",
|
||||
"Enable Encryption" => "Ενεργοποίηση Κρυπτογράφησης"
|
||||
"None" => "Καμία"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Ĉifrado",
|
||||
"Exclude the following file types from encryption" => "Malinkluzivigi la jenajn dosiertipojn el ĉifrado",
|
||||
"None" => "Nenio",
|
||||
"Enable Encryption" => "Kapabligi ĉifradon"
|
||||
"None" => "Nenio"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Cifrado",
|
||||
"Exclude the following file types from encryption" => "Excluir del cifrado los siguientes tipos de archivo",
|
||||
"None" => "Ninguno",
|
||||
"Enable Encryption" => "Habilitar cifrado"
|
||||
"None" => "Ninguno"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Encriptación",
|
||||
"Exclude the following file types from encryption" => "Exceptuar de la encriptación los siguientes tipos de archivo",
|
||||
"None" => "Ninguno",
|
||||
"Enable Encryption" => "Habilitar encriptación"
|
||||
"None" => "Ninguno"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Krüpteerimine",
|
||||
"Exclude the following file types from encryption" => "Järgnevaid failitüüpe ära krüpteeri",
|
||||
"None" => "Pole",
|
||||
"Enable Encryption" => "Luba krüpteerimine"
|
||||
"None" => "Pole"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Enkriptazioa",
|
||||
"Exclude the following file types from encryption" => "Ez enkriptatu hurrengo fitxategi motak",
|
||||
"None" => "Bat ere ez",
|
||||
"Enable Encryption" => "Gaitu enkriptazioa"
|
||||
"None" => "Bat ere ez"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "رمزگذاری",
|
||||
"Exclude the following file types from encryption" => "نادیده گرفتن فایل های زیر برای رمز گذاری",
|
||||
"None" => "هیچکدام",
|
||||
"Enable Encryption" => "فعال کردن رمزگذاری"
|
||||
"None" => "هیچکدام"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Salaus",
|
||||
"Exclude the following file types from encryption" => "Jätä seuraavat tiedostotyypit salaamatta",
|
||||
"None" => "Ei mitään",
|
||||
"Enable Encryption" => "Käytä salausta"
|
||||
"None" => "Ei mitään"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Chiffrement",
|
||||
"Exclude the following file types from encryption" => "Ne pas chiffrer les fichiers dont les types sont les suivants",
|
||||
"None" => "Aucun",
|
||||
"Enable Encryption" => "Activer le chiffrement"
|
||||
"None" => "Aucun"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Cifrado",
|
||||
"Exclude the following file types from encryption" => "Excluír os seguintes tipos de ficheiro do cifrado",
|
||||
"None" => "Nada",
|
||||
"Enable Encryption" => "Activar o cifrado"
|
||||
"None" => "Nada"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "הצפנה",
|
||||
"Enable Encryption" => "הפעל הצפנה",
|
||||
"None" => "כלום",
|
||||
"Exclude the following file types from encryption" => "הוצא את סוגי הקבצים הבאים מהצפנה"
|
||||
"Exclude the following file types from encryption" => "הוצא את סוגי הקבצים הבאים מהצפנה",
|
||||
"None" => "כלום"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Titkosítás",
|
||||
"Enable Encryption" => "A titkosítás engedélyezése",
|
||||
"None" => "Egyik sem",
|
||||
"Exclude the following file types from encryption" => "A következő fájltípusok kizárása a titkosításból"
|
||||
"Exclude the following file types from encryption" => "A következő fájltípusok kizárása a titkosításból",
|
||||
"None" => "Egyik sem"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "enkripsi",
|
||||
"Exclude the following file types from encryption" => "pengecualian untuk tipe file berikut dari enkripsi",
|
||||
"None" => "tidak ada",
|
||||
"Enable Encryption" => "aktifkan enkripsi"
|
||||
"None" => "tidak ada"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Dulkóðun",
|
||||
"Enable Encryption" => "Virkja dulkóðun",
|
||||
"None" => "Ekkert",
|
||||
"Exclude the following file types from encryption" => "Undanskilja eftirfarandi skráartegundir frá dulkóðun"
|
||||
"Exclude the following file types from encryption" => "Undanskilja eftirfarandi skráartegundir frá dulkóðun",
|
||||
"None" => "Ekkert"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Cifratura",
|
||||
"Exclude the following file types from encryption" => "Escludi i seguenti tipi di file dalla cifratura",
|
||||
"None" => "Nessuna",
|
||||
"Enable Encryption" => "Abilita cifratura"
|
||||
"None" => "Nessuna"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "暗号化",
|
||||
"Exclude the following file types from encryption" => "暗号化から除外するファイルタイプ",
|
||||
"None" => "なし",
|
||||
"Enable Encryption" => "暗号化を有効にする"
|
||||
"None" => "なし"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "암호화",
|
||||
"Exclude the following file types from encryption" => "다음 파일 형식은 암호화하지 않음",
|
||||
"None" => "없음",
|
||||
"Enable Encryption" => "암호화 사용"
|
||||
"None" => "없음"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "نهێنیکردن",
|
||||
"Exclude the following file types from encryption" => "بهربهست کردنی ئهم جۆره پهڕگانه له نهێنیکردن",
|
||||
"None" => "هیچ",
|
||||
"Enable Encryption" => "چالاکردنی نهێنیکردن"
|
||||
"None" => "هیچ"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Šifravimas",
|
||||
"Exclude the following file types from encryption" => "Nešifruoti pasirinkto tipo failų",
|
||||
"None" => "Nieko",
|
||||
"Enable Encryption" => "Įjungti šifravimą"
|
||||
"None" => "Nieko"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Енкрипција",
|
||||
"Exclude the following file types from encryption" => "Исклучи ги следните типови на датотеки од енкрипција",
|
||||
"None" => "Ништо",
|
||||
"Enable Encryption" => "Овозможи енкрипција"
|
||||
"None" => "Ништо"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Kryptering",
|
||||
"Exclude the following file types from encryption" => "Ekskluder følgende filer fra kryptering",
|
||||
"None" => "Ingen",
|
||||
"Enable Encryption" => "Slå på kryptering"
|
||||
"None" => "Ingen"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Versleuteling",
|
||||
"Exclude the following file types from encryption" => "Versleutel de volgende bestand types niet",
|
||||
"None" => "Geen",
|
||||
"Enable Encryption" => "Zet versleuteling aan"
|
||||
"None" => "Geen"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Szyfrowanie",
|
||||
"Exclude the following file types from encryption" => "Wyłącz następujące typy plików z szyfrowania",
|
||||
"None" => "Brak",
|
||||
"Enable Encryption" => "Włącz szyfrowanie"
|
||||
"None" => "Brak"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Criptografia",
|
||||
"Exclude the following file types from encryption" => "Excluir os seguintes tipos de arquivo da criptografia",
|
||||
"None" => "Nenhuma",
|
||||
"Enable Encryption" => "Habilitar Criptografia"
|
||||
"None" => "Nenhuma"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Encriptação",
|
||||
"Exclude the following file types from encryption" => "Excluir da encriptação os seguintes tipo de ficheiros",
|
||||
"None" => "Nenhum",
|
||||
"Enable Encryption" => "Activar Encriptação"
|
||||
"None" => "Nenhum"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Încriptare",
|
||||
"Exclude the following file types from encryption" => "Exclude următoarele tipuri de fișiere de la încriptare",
|
||||
"None" => "Niciuna",
|
||||
"Enable Encryption" => "Activare încriptare"
|
||||
"None" => "Niciuna"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Шифрование",
|
||||
"Exclude the following file types from encryption" => "Исключить шифрование следующих типов файлов",
|
||||
"None" => "Ничего",
|
||||
"Enable Encryption" => "Включить шифрование"
|
||||
"None" => "Ничего"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Шифрование",
|
||||
"Exclude the following file types from encryption" => "Исключите следующие типы файлов из шифрования",
|
||||
"None" => "Ни один",
|
||||
"Enable Encryption" => "Включить шифрование"
|
||||
"None" => "Ни один"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "ගුප්ත කේතනය",
|
||||
"Exclude the following file types from encryption" => "මෙම ගොනු වර්ග ගුප්ත කේතනය කිරීමෙන් බැහැරව තබන්න",
|
||||
"None" => "කිසිවක් නැත",
|
||||
"Enable Encryption" => "ගුප්ත කේතනය සක්රිය කරන්න"
|
||||
"None" => "කිසිවක් නැත"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Šifrovanie",
|
||||
"Exclude the following file types from encryption" => "Vynechať nasledujúce súbory pri šifrovaní",
|
||||
"None" => "Žiadne",
|
||||
"Enable Encryption" => "Zapnúť šifrovanie"
|
||||
"None" => "Žiadne"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Šifriranje",
|
||||
"Exclude the following file types from encryption" => "Navedene vrste datotek naj ne bodo šifrirane",
|
||||
"None" => "Brez",
|
||||
"Enable Encryption" => "Omogoči šifriranje"
|
||||
"None" => "Brez"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Шифровање",
|
||||
"Exclude the following file types from encryption" => "Не шифруј следеће типове датотека",
|
||||
"None" => "Ништа",
|
||||
"Enable Encryption" => "Омогући шифровање"
|
||||
"None" => "Ништа"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Kryptering",
|
||||
"Exclude the following file types from encryption" => "Exkludera följande filtyper från kryptering",
|
||||
"None" => "Ingen",
|
||||
"Enable Encryption" => "Aktivera kryptering"
|
||||
"None" => "Ingen"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "மறைக்குறியீடு",
|
||||
"Exclude the following file types from encryption" => "மறைக்குறியாக்கலில் பின்வரும் கோப்பு வகைகளை நீக்கவும்",
|
||||
"None" => "ஒன்றுமில்லை",
|
||||
"Enable Encryption" => "மறைக்குறியாக்கலை இயலுமைப்படுத்துக"
|
||||
"None" => "ஒன்றுமில்லை"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "การเข้ารหัส",
|
||||
"Exclude the following file types from encryption" => "ไม่ต้องรวมชนิดของไฟล์ดังต่อไปนี้จากการเข้ารหัส",
|
||||
"None" => "ไม่ต้อง",
|
||||
"Enable Encryption" => "เปิดใช้งานการเข้ารหัส"
|
||||
"None" => "ไม่ต้อง"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Şifreleme",
|
||||
"Enable Encryption" => "Şifrelemeyi Etkinleştir",
|
||||
"None" => "Hiçbiri",
|
||||
"Exclude the following file types from encryption" => "Aşağıdaki dosya tiplerini şifrelemeye dahil etme"
|
||||
"Exclude the following file types from encryption" => "Aşağıdaki dosya tiplerini şifrelemeye dahil etme",
|
||||
"None" => "Hiçbiri"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Шифрування",
|
||||
"Exclude the following file types from encryption" => "Не шифрувати файли наступних типів",
|
||||
"None" => "Жоден",
|
||||
"Enable Encryption" => "Включити шифрування"
|
||||
"None" => "Жоден"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "Mã hóa",
|
||||
"Exclude the following file types from encryption" => "Loại trừ các loại tập tin sau đây từ mã hóa",
|
||||
"None" => "Không có gì hết",
|
||||
"Enable Encryption" => "BẬT mã hóa"
|
||||
"None" => "Không có gì hết"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "加密",
|
||||
"Exclude the following file types from encryption" => "从加密中排除如下文件类型",
|
||||
"None" => "无",
|
||||
"Enable Encryption" => "启用加密"
|
||||
"None" => "无"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "加密",
|
||||
"Exclude the following file types from encryption" => "从加密中排除列出的文件类型",
|
||||
"None" => "None",
|
||||
"Enable Encryption" => "开启加密"
|
||||
"None" => "None"
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"Encryption" => "加密",
|
||||
"Exclude the following file types from encryption" => "下列的檔案類型不加密",
|
||||
"None" => "無",
|
||||
"Enable Encryption" => "啟用加密"
|
||||
"None" => "無"
|
||||
);
|
||||
|
|
952
apps/files_encryption/lib/crypt.php
Normal file → Executable file
952
apps/files_encryption/lib/crypt.php
Normal file → Executable file
|
@ -1,220 +1,732 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Frank Karlitschek
|
||||
* @copyright 2012 Frank Karlitschek frank@owncloud.org
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Todo:
|
||||
// - Crypt/decrypt button in the userinterface
|
||||
// - Setting if crypto should be on by default
|
||||
// - Add a setting "Don´t encrypt files larger than xx because of performance reasons"
|
||||
// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is encrypted (.encrypted extension)
|
||||
// - Don't use a password directly as encryption key, but a key which is stored on the server and encrypted with the
|
||||
// user password. -> password change faster
|
||||
// - IMPORTANT! Check if the block lenght of the encrypted data stays the same
|
||||
|
||||
|
||||
require_once 'Crypt_Blowfish/Blowfish.php';
|
||||
|
||||
/**
|
||||
* This class is for crypting and decrypting
|
||||
*/
|
||||
class OC_Crypt {
|
||||
static private $bf = null;
|
||||
|
||||
public static function loginListener($params) {
|
||||
self::init($params['uid'], $params['password']);
|
||||
}
|
||||
|
||||
public static function init($login, $password) {
|
||||
$view=new OC_FilesystemView('/');
|
||||
if ( ! $view->file_exists('/'.$login)) {
|
||||
$view->mkdir('/'.$login);
|
||||
}
|
||||
|
||||
OC_FileProxy::$enabled=false;
|
||||
if ( ! $view->file_exists('/'.$login.'/encryption.key')) {// does key exist?
|
||||
OC_Crypt::createkey($login, $password);
|
||||
}
|
||||
$key=$view->file_get_contents('/'.$login.'/encryption.key');
|
||||
OC_FileProxy::$enabled=true;
|
||||
$_SESSION['enckey']=OC_Crypt::decrypt($key, $password);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get the blowfish encryption handeler for a key
|
||||
* @param string $key (optional)
|
||||
* @return Crypt_Blowfish
|
||||
*
|
||||
* 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 {
|
||||
if ( ! isset($_SESSION['enckey'])) {
|
||||
return false;
|
||||
}
|
||||
if ( ! self::$bf) {
|
||||
self::$bf=new Crypt_Blowfish($_SESSION['enckey']);
|
||||
}
|
||||
return self::$bf;
|
||||
}
|
||||
}
|
||||
|
||||
public static function createkey($username, $passcode) {
|
||||
// generate a random key
|
||||
$key=mt_rand(10000, 99999).mt_rand(10000, 99999).mt_rand(10000, 99999).mt_rand(10000, 99999);
|
||||
|
||||
// encrypt the key with the passcode of the user
|
||||
$enckey=OC_Crypt::encrypt($key, $passcode);
|
||||
|
||||
// Write the file
|
||||
$proxyEnabled=OC_FileProxy::$enabled;
|
||||
OC_FileProxy::$enabled=false;
|
||||
$view=new OC_FilesystemView('/'.$username);
|
||||
$view->file_put_contents('/encryption.key', $enckey);
|
||||
OC_FileProxy::$enabled=$proxyEnabled;
|
||||
}
|
||||
|
||||
public static function changekeypasscode($oldPassword, $newPassword) {
|
||||
if (OCP\User::isLoggedIn()) {
|
||||
$username=OCP\USER::getUser();
|
||||
$view=new OC_FilesystemView('/'.$username);
|
||||
|
||||
// read old key
|
||||
$key=$view->file_get_contents('/encryption.key');
|
||||
|
||||
// decrypt key with old passcode
|
||||
$key=OC_Crypt::decrypt($key, $oldPassword);
|
||||
|
||||
// encrypt again with new passcode
|
||||
$key=OC_Crypt::encrypt($key, $newPassword);
|
||||
|
||||
// store the new key
|
||||
$view->file_put_contents('/encryption.key', $key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief encrypts an content
|
||||
* @param $content the cleartext message you want to encrypt
|
||||
* @param $key the encryption key (optional)
|
||||
* @returns encrypted content
|
||||
*
|
||||
* This function encrypts an content
|
||||
*/
|
||||
public static function encrypt( $content, $key='') {
|
||||
$bf = self::getBlowfish($key);
|
||||
return $bf->encrypt($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief decryption of an content
|
||||
* @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 decrypt( $content, $key='') {
|
||||
$bf = self::getBlowfish($key);
|
||||
$data=$bf->decrypt($content);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief encryption of a file
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $key the decryption key
|
||||
*
|
||||
* This function encrypts a file
|
||||
*/
|
||||
public static function encryptFile( $source, $target, $key='') {
|
||||
$handleread = fopen($source, "rb");
|
||||
if ($handleread!=false) {
|
||||
$handlewrite = fopen($target, "wb");
|
||||
while (!feof($handleread)) {
|
||||
$content = fread($handleread, 8192);
|
||||
$enccontent=OC_CRYPT::encrypt( $content, $key);
|
||||
fwrite($handlewrite, $enccontent);
|
||||
}
|
||||
fclose($handlewrite);
|
||||
fclose($handleread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief decryption of a file
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $key the decryption key
|
||||
*
|
||||
* This function decrypts a file
|
||||
*/
|
||||
public static function decryptFile( $source, $target, $key='') {
|
||||
$handleread = fopen($source, "rb");
|
||||
if ($handleread!=false) {
|
||||
$handlewrite = fopen($target, "wb");
|
||||
while (!feof($handleread)) {
|
||||
$content = fread($handleread, 8192);
|
||||
$enccontent=OC_CRYPT::decrypt( $content, $key);
|
||||
if (feof($handleread)) {
|
||||
$enccontent=rtrim($enccontent, "\0");
|
||||
}
|
||||
fwrite($handlewrite, $enccontent);
|
||||
}
|
||||
fclose($handlewrite);
|
||||
fclose($handleread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* encrypt data in 8192b sized blocks
|
||||
*/
|
||||
public static function blockEncrypt($data, $key='') {
|
||||
$result='';
|
||||
while (strlen($data)) {
|
||||
$result.=self::encrypt(substr($data, 0, 8192), $key);
|
||||
$data=substr($data, 8192);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypt data in 8192b sized blocks
|
||||
*/
|
||||
public static function blockDecrypt($data, $key='', $maxLength=0) {
|
||||
$result='';
|
||||
while (strlen($data)) {
|
||||
$result.=self::decrypt(substr($data, 0, 8192), $key);
|
||||
$data=substr($data, 8192);
|
||||
}
|
||||
if ($maxLength>0) {
|
||||
return substr($result, 0, $maxLength);
|
||||
} else {
|
||||
return rtrim($result, "\0");
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke, Frank Karlitschek, Robin Appelman
|
||||
* @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
|
||||
* 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;
|
||||
|
||||
require_once 'Crypt_Blowfish/Blowfish.php';
|
||||
|
||||
// Todo:
|
||||
// - Crypt/decrypt button in the userinterface
|
||||
// - Setting if crypto should be on by default
|
||||
// - Add a setting "Don´t encrypt files larger than xx because of performance reasons"
|
||||
// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is encrypted (.encrypted extension)
|
||||
// - Don't use a password directly as encryption key. but a key which is stored on the server and encrypted with the user password. -> password change faster
|
||||
// - IMPORTANT! Check if the block lenght of the encrypted data stays the same
|
||||
|
||||
/**
|
||||
* Class for common cryptography functionality
|
||||
*/
|
||||
|
||||
class Crypt {
|
||||
|
||||
/**
|
||||
* @brief return encryption mode client or server side encryption
|
||||
* @param string user name (use system wide setting if name=null)
|
||||
* @return string 'client' or 'server'
|
||||
*/
|
||||
public static function mode( $user = null ) {
|
||||
|
||||
// $mode = \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' );
|
||||
//
|
||||
// if ( $mode == 'user') {
|
||||
// if ( !$user ) {
|
||||
// $user = \OCP\User::getUser();
|
||||
// }
|
||||
// $mode = 'none';
|
||||
// if ( $user ) {
|
||||
// $query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" );
|
||||
// $result = $query->execute(array($user));
|
||||
// if ($row = $result->fetchRow()){
|
||||
// $mode = $row['mode'];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return $mode;
|
||||
|
||||
return 'server';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new encryption keypair
|
||||
* @return array publicKey, privatekey
|
||||
*/
|
||||
public static function createKeypair() {
|
||||
|
||||
$res = openssl_pkey_new();
|
||||
|
||||
// Get private key
|
||||
openssl_pkey_export( $res, $privateKey );
|
||||
|
||||
// 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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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()
|
||||
*/
|
||||
public static function isEncryptedContent( $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_FileCache_Cached out of here
|
||||
|
||||
// Fetch all file metadata from DB
|
||||
$metadata = \OC_FileCache_Cached::get( $path, '' );
|
||||
|
||||
// Return encryption status
|
||||
return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a file is encrypted via legacy system
|
||||
* @return true / false
|
||||
*/
|
||||
public static function isLegacyEncryptedContent( $content ) {
|
||||
|
||||
// Fetch all file metadata from DB
|
||||
$metadata = \OC_FileCache_Cached::get( $content, '' );
|
||||
|
||||
// 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 (
|
||||
$content
|
||||
and isset( $metadata['encrypted'] )
|
||||
and $metadata['encrypted'] === true
|
||||
and !self::isEncryptedContent( $content )
|
||||
) {
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
);
|
||||
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
} 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static function symmetricEncryptFileContentKeyfile( $plainContent ) {
|
||||
|
||||
$key = self::generateKey();
|
||||
|
||||
if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) {
|
||||
|
||||
return array(
|
||||
'key' => $key
|
||||
, '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
|
||||
*/
|
||||
public static function multiKeyEncrypt( $plainContent, array $publicKeys ) {
|
||||
|
||||
$envKeys = array();
|
||||
|
||||
if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {
|
||||
|
||||
return array(
|
||||
'keys' => $envKeys
|
||||
, '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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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()' );
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
* @return Crypt_Blowfish blowfish object
|
||||
*
|
||||
* 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 );
|
||||
|
||||
// Encrypt the key with the passphrase
|
||||
$legacyEncKey = self::legacyEncrypt( $key, $passphrase );
|
||||
|
||||
return $legacyEncKey;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief encrypts content using legacy blowfish system
|
||||
* @param $content the cleartext message you want to encrypt
|
||||
* @param $key the encryption key (optional)
|
||||
* @returns encrypted content
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) {
|
||||
|
||||
# TODO: write me
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,177 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Robin Appelman
|
||||
* @copyright 2011 Robin Appelman icewind1991@gmail.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* transparently encrypted filestream
|
||||
*
|
||||
* you can use it as wrapper around an existing stream by setting
|
||||
* OC_CryptStream::$sourceStreams['foo']=array('path'=>$path, 'stream'=>$stream)
|
||||
* and then fopen('crypt://streams/foo');
|
||||
*/
|
||||
|
||||
class OC_CryptStream{
|
||||
public static $sourceStreams=array();
|
||||
private $source;
|
||||
private $path;
|
||||
private $meta=array();//header/meta for source stream
|
||||
private $writeCache;
|
||||
private $size;
|
||||
private static $rootView;
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
if ( ! self::$rootView) {
|
||||
self::$rootView=new OC_FilesystemView('');
|
||||
}
|
||||
$path=str_replace('crypt://', '', $path);
|
||||
if (dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])) {
|
||||
$this->source=self::$sourceStreams[basename($path)]['stream'];
|
||||
$this->path=self::$sourceStreams[basename($path)]['path'];
|
||||
$this->size=self::$sourceStreams[basename($path)]['size'];
|
||||
} else {
|
||||
$this->path=$path;
|
||||
if ($mode=='w' or $mode=='w+' or $mode=='wb' or $mode=='wb+') {
|
||||
$this->size=0;
|
||||
} else {
|
||||
$this->size=self::$rootView->filesize($path, $mode);
|
||||
}
|
||||
OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file
|
||||
$this->source=self::$rootView->fopen($path, $mode);
|
||||
OC_FileProxy::$enabled=true;
|
||||
if ( ! is_resource($this->source)) {
|
||||
OCP\Util::writeLog('files_encryption', 'failed to open '.$path, OCP\Util::ERROR);
|
||||
}
|
||||
}
|
||||
if (is_resource($this->source)) {
|
||||
$this->meta=stream_get_meta_data($this->source);
|
||||
}
|
||||
return is_resource($this->source);
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence=SEEK_SET) {
|
||||
$this->flush();
|
||||
fseek($this->source, $offset, $whence);
|
||||
}
|
||||
|
||||
public function stream_tell() {
|
||||
return ftell($this->source);
|
||||
}
|
||||
|
||||
public function stream_read($count) {
|
||||
//$count will always be 8192 https://bugs.php.net/bug.php?id=21641
|
||||
//This makes this function a lot simpler but will breake everything the moment it's fixed
|
||||
$this->writeCache='';
|
||||
if ($count!=8192) {
|
||||
OCP\Util::writeLog('files_encryption',
|
||||
'php bug 21641 no longer holds, decryption will not work',
|
||||
OCP\Util::FATAL);
|
||||
die();
|
||||
}
|
||||
$pos=ftell($this->source);
|
||||
$data=fread($this->source, 8192);
|
||||
if (strlen($data)) {
|
||||
$result=OC_Crypt::decrypt($data);
|
||||
} else {
|
||||
$result='';
|
||||
}
|
||||
$length=$this->size-$pos;
|
||||
if ($length<8192) {
|
||||
$result=substr($result, 0, $length);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function stream_write($data) {
|
||||
$length=strlen($data);
|
||||
$currentPos=ftell($this->source);
|
||||
if ($this->writeCache) {
|
||||
$data=$this->writeCache.$data;
|
||||
$this->writeCache='';
|
||||
}
|
||||
if ($currentPos%8192!=0) {
|
||||
//make sure we always start on a block start
|
||||
fseek($this->source, -($currentPos%8192), SEEK_CUR);
|
||||
$encryptedBlock=fread($this->source, 8192);
|
||||
fseek($this->source, -($currentPos%8192), SEEK_CUR);
|
||||
$block=OC_Crypt::decrypt($encryptedBlock);
|
||||
$data=substr($block, 0, $currentPos%8192).$data;
|
||||
fseek($this->source, -($currentPos%8192), SEEK_CUR);
|
||||
}
|
||||
$currentPos=ftell($this->source);
|
||||
while ($remainingLength=strlen($data)>0) {
|
||||
if ($remainingLength<8192) {
|
||||
$this->writeCache=$data;
|
||||
$data='';
|
||||
} else {
|
||||
$encrypted=OC_Crypt::encrypt(substr($data, 0, 8192));
|
||||
fwrite($this->source, $encrypted);
|
||||
$data=substr($data, 8192);
|
||||
}
|
||||
}
|
||||
$this->size=max($this->size, $currentPos+$length);
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2) {
|
||||
switch($option) {
|
||||
case STREAM_OPTION_BLOCKING:
|
||||
stream_set_blocking($this->source, $arg1);
|
||||
break;
|
||||
case STREAM_OPTION_READ_TIMEOUT:
|
||||
stream_set_timeout($this->source, $arg1, $arg2);
|
||||
break;
|
||||
case STREAM_OPTION_WRITE_BUFFER:
|
||||
stream_set_write_buffer($this->source, $arg1, $arg2);
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_stat() {
|
||||
return fstat($this->source);
|
||||
}
|
||||
|
||||
public function stream_lock($mode) {
|
||||
flock($this->source, $mode);
|
||||
}
|
||||
|
||||
public function stream_flush() {
|
||||
return fflush($this->source);
|
||||
}
|
||||
|
||||
public function stream_eof() {
|
||||
return feof($this->source);
|
||||
}
|
||||
|
||||
private function flush() {
|
||||
if ($this->writeCache) {
|
||||
$encrypted=OC_Crypt::encrypt($this->writeCache);
|
||||
fwrite($this->source, $encrypted);
|
||||
$this->writeCache='';
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_close() {
|
||||
$this->flush();
|
||||
if ($this->meta['mode']!='r' and $this->meta['mode']!='rb') {
|
||||
OC_FileCache::put($this->path, array('encrypted'=>true, 'size'=>$this->size), '');
|
||||
}
|
||||
return fclose($this->source);
|
||||
}
|
||||
}
|
365
apps/files_encryption/lib/keymanager.php
Executable file
365
apps/files_encryption/lib/keymanager.php
Executable file
|
@ -0,0 +1,365 @@
|
|||
<?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 {
|
||||
|
||||
# TODO: make all dependencies (including static classes) explicit, such as ocfsview objects, by adding them as method arguments (dependency injection)
|
||||
|
||||
/**
|
||||
* @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' ) ) {
|
||||
|
||||
// // Check if file was shared with other users
|
||||
// $query = \OC_DB::prepare( "
|
||||
// SELECT
|
||||
// uid_owner
|
||||
// , source
|
||||
// , target
|
||||
// , uid_shared_with
|
||||
// FROM
|
||||
// `*PREFIX*sharing`
|
||||
// WHERE
|
||||
// ( target = ? AND uid_shared_with = ? )
|
||||
// OR source = ?
|
||||
// " );
|
||||
//
|
||||
// $result = $query->execute( array ( $filepath, $userId, $filepath ) );
|
||||
//
|
||||
// $users = array();
|
||||
//
|
||||
// if ( $row = $result->fetchRow() )
|
||||
// {
|
||||
// $source = $row['source'];
|
||||
// $owner = $row['uid_owner'];
|
||||
// $users[] = $owner;
|
||||
// // get the uids of all user with access to the file
|
||||
// $query = \OC_DB::prepare( "SELECT source, uid_shared_with FROM `*PREFIX*sharing` WHERE source = ?" );
|
||||
// $result = $query->execute( array ($source));
|
||||
// while ( ($row = $result->fetchRow()) ) {
|
||||
// $users[] = $row['uid_shared_with'];
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
} 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 retrieve keyfile for an encrypted file
|
||||
* @param string file 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, '/' );
|
||||
|
||||
// // update $keypath and $userId if path point to a file shared by someone else
|
||||
// $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" );
|
||||
//
|
||||
// $result = $query->execute( array ('/'.$userId.'/files/'.$keypath, $userId));
|
||||
//
|
||||
// if ($row = $result->fetchRow()) {
|
||||
//
|
||||
// $keypath = $row['source'];
|
||||
// $keypath_parts = explode( '/', $keypath );
|
||||
// $userId = $keypath_parts[1];
|
||||
// $keypath = str_replace( '/' . $userId . '/files/', '', $keypath );
|
||||
//
|
||||
// }
|
||||
|
||||
return $view->file_get_contents( '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief retrieve file encryption key
|
||||
*
|
||||
* @param string file name
|
||||
* @return string file key or false
|
||||
*/
|
||||
public static function deleteFileKey( $path, $staticUserClass = 'OCP\User' ) {
|
||||
|
||||
$keypath = ltrim( $path, '/' );
|
||||
$user = $staticUserClass::getUser();
|
||||
|
||||
// update $keypath and $user if path point to a file shared by someone else
|
||||
// $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" );
|
||||
//
|
||||
// $result = $query->execute( array ('/'.$user.'/files/'.$keypath, $user));
|
||||
//
|
||||
// if ($row = $result->fetchRow()) {
|
||||
//
|
||||
// $keypath = $row['source'];
|
||||
// $keypath_parts = explode( '/', $keypath );
|
||||
// $user = $keypath_parts[1];
|
||||
// $keypath = str_replace( '/' . $user . '/files/', '', $keypath );
|
||||
//
|
||||
// }
|
||||
|
||||
$view = new \OC_FilesystemView('/'.$user.'/files_encryption/keyfiles/');
|
||||
|
||||
return $view->unlink( $keypath . '.key' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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( $path, $key, $view = Null, $dbClassName = '\OC_DB') {
|
||||
|
||||
$targetPath = ltrim( $path, '/' );
|
||||
$user = \OCP\User::getUser();
|
||||
|
||||
// // update $keytarget and $user if key belongs to a file shared by someone else
|
||||
// $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" );
|
||||
//
|
||||
// $result = $query->execute( array ( '/'.$user.'/files/'.$targetPath, $user ) );
|
||||
//
|
||||
// if ( $row = $result->fetchRow( ) ) {
|
||||
//
|
||||
// $targetPath = $row['source'];
|
||||
//
|
||||
// $targetPath_parts = explode( '/', $targetPath );
|
||||
//
|
||||
// $user = $targetPath_parts[1];
|
||||
//
|
||||
// $rootview = new \OC_FilesystemView( '/' );
|
||||
//
|
||||
// if ( ! $rootview->is_writable( $targetPath ) ) {
|
||||
//
|
||||
// \OC_Log::write( 'Encryption library', "File Key not updated because you don't have write access for the corresponding file", \OC_Log::ERROR );
|
||||
//
|
||||
// return false;
|
||||
//
|
||||
// }
|
||||
//
|
||||
// $targetPath = str_replace( '/'.$user.'/files/', '', $targetPath );
|
||||
//
|
||||
// //TODO: check for write permission on shared file once the new sharing API is in place
|
||||
//
|
||||
// }
|
||||
|
||||
$path_parts = pathinfo( $targetPath );
|
||||
|
||||
if ( !$view ) {
|
||||
|
||||
$view = new \OC_FilesystemView( '/' );
|
||||
|
||||
}
|
||||
|
||||
$view->chroot( '/' . $user . '/files_encryption/keyfiles' );
|
||||
|
||||
// If the file resides within a subdirectory, create it
|
||||
if (
|
||||
isset( $path_parts['dirname'] )
|
||||
&& ! $view->file_exists( $path_parts['dirname'] )
|
||||
) {
|
||||
|
||||
$view->mkdir( $path_parts['dirname'] );
|
||||
|
||||
}
|
||||
|
||||
// Save the keyfile in parallel directory
|
||||
return $view->file_put_contents( '/' . $targetPath . '.key', $key );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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' );
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3,8 +3,9 @@
|
|||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Robin Appelman
|
||||
* @copyright 2011 Robin Appelman icewind1991@gmail.com
|
||||
* @author Sam Tuke, Robin Appelman
|
||||
* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
|
||||
* icewind1991@gmail.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
|
@ -21,111 +22,267 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* transparent encryption
|
||||
*/
|
||||
namespace OCA\Encryption;
|
||||
|
||||
class OC_FileProxy_Encryption extends OC_FileProxy{
|
||||
private static $blackList=null; //mimetypes blacklisted from encryption
|
||||
private static $enableEncryption=null;
|
||||
class Proxy extends \OC_FileProxy {
|
||||
|
||||
private static $blackList = null; //mimetypes blacklisted from encryption
|
||||
|
||||
private static $enableEncryption = null;
|
||||
|
||||
/**
|
||||
* check if a file should be encrypted during write
|
||||
* Check if a file requires encryption
|
||||
* @param string $path
|
||||
* @return bool
|
||||
*
|
||||
* Tests if server side encryption is enabled, and file is allowed by blacklists
|
||||
*/
|
||||
private static function shouldEncrypt($path) {
|
||||
if (is_null(self::$enableEncryption)) {
|
||||
self::$enableEncryption=(OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true')=='true');
|
||||
private static function shouldEncrypt( $path ) {
|
||||
|
||||
if ( is_null( self::$enableEncryption ) ) {
|
||||
|
||||
if (
|
||||
\OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true'
|
||||
&& Crypt::mode() == 'server'
|
||||
) {
|
||||
|
||||
self::$enableEncryption = true;
|
||||
|
||||
} else {
|
||||
|
||||
self::$enableEncryption = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if ( ! self::$enableEncryption) {
|
||||
|
||||
if ( !self::$enableEncryption ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
if (is_null(self::$blackList)) {
|
||||
self::$blackList=explode(',', OCP\Config::getAppValue('files_encryption',
|
||||
'type_blacklist',
|
||||
'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg'));
|
||||
|
||||
if ( is_null(self::$blackList ) ) {
|
||||
|
||||
self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) );
|
||||
|
||||
}
|
||||
if (self::isEncrypted($path)) {
|
||||
|
||||
if ( Crypt::isEncryptedContent( $path ) ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
$extension=substr($path, strrpos($path, '.')+1);
|
||||
if (array_search($extension, self::$blackList)===false) {
|
||||
|
||||
$extension = substr( $path, strrpos( $path,'.' ) +1 );
|
||||
|
||||
if ( array_search( $extension, self::$blackList ) === false ){
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function preFile_put_contents( $path, &$data ) {
|
||||
|
||||
if ( self::shouldEncrypt( $path ) ) {
|
||||
|
||||
if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen
|
||||
|
||||
$userId = \OCP\USER::getUser();
|
||||
|
||||
$rootView = new \OC_FilesystemView( '/' );
|
||||
|
||||
// Set the filesize for userland, before encrypting
|
||||
$size = strlen( $data );
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Encrypt plain data and fetch key
|
||||
$encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) );
|
||||
|
||||
// Replace plain content with encrypted content by reference
|
||||
$data = $encrypted['data'];
|
||||
|
||||
$filePath = explode( '/', $path );
|
||||
|
||||
$filePath = array_slice( $filePath, 3 );
|
||||
|
||||
$filePath = '/' . implode( '/', $filePath );
|
||||
|
||||
# TODO: make keyfile dir dynamic from app config
|
||||
$view = new \OC_FilesystemView( '/' . $userId . '/files_encryption/keyfiles' );
|
||||
|
||||
// Save keyfile for newly encrypted file in parallel directory tree
|
||||
Keymanager::setFileKey( $filePath, $encrypted['key'], $view, '\OC_DB' );
|
||||
|
||||
// Update the file cache with file info
|
||||
\OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
|
||||
|
||||
// Re-enable proxy - our work is done
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a file is encrypted
|
||||
* @param string $path
|
||||
* @return bool
|
||||
* @param string $path Path of file from which has been read
|
||||
* @param string $data Data that has been read from file
|
||||
*/
|
||||
private static function isEncrypted($path) {
|
||||
$metadata=OC_FileCache_Cached::get($path, '');
|
||||
return isset($metadata['encrypted']) and (bool)$metadata['encrypted'];
|
||||
}
|
||||
public function postFile_get_contents( $path, $data ) {
|
||||
|
||||
# TODO: Use dependency injection to add required args for view and user etc. to this method
|
||||
|
||||
public function preFile_put_contents($path,&$data) {
|
||||
if (self::shouldEncrypt($path)) {
|
||||
if ( ! is_resource($data)) {//stream put contents should have been converter to fopen
|
||||
$size=strlen($data);
|
||||
$data=OC_Crypt::blockEncrypt($data);
|
||||
OC_FileCache::put($path, array('encrypted'=>true,'size'=>$size), '');
|
||||
}
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// If data is a catfile
|
||||
if (
|
||||
Crypt::mode() == 'server'
|
||||
&& Crypt::isEncryptedContent( $data )
|
||||
) {
|
||||
|
||||
$split = explode( '/', $path );
|
||||
|
||||
$filePath = array_slice( $split, 3 );
|
||||
|
||||
$filePath = '/' . implode( '/', $filePath );
|
||||
|
||||
//$cached = \OC_FileCache_Cached::get( $path, '' );
|
||||
|
||||
$view = new \OC_FilesystemView( '' );
|
||||
|
||||
$userId = \OCP\USER::getUser();
|
||||
|
||||
$encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
|
||||
|
||||
$session = new Session();
|
||||
|
||||
$decrypted = Crypt::keyDecryptKeyfile( $data, $encryptedKeyfile, $session->getPrivateKey( $split[1] ) );
|
||||
|
||||
} elseif (
|
||||
Crypt::mode() == 'server'
|
||||
&& isset( $_SESSION['legacyenckey'] )
|
||||
&& Crypt::isEncryptedMeta( $path )
|
||||
) {
|
||||
|
||||
$decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function postFile_get_contents($path, $data) {
|
||||
if (self::isEncrypted($path)) {
|
||||
$cached=OC_FileCache_Cached::get($path, '');
|
||||
$data=OC_Crypt::blockDecrypt($data, '', $cached['size']);
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
if ( ! isset( $decrypted ) ) {
|
||||
|
||||
$decrypted = $data;
|
||||
|
||||
}
|
||||
return $data;
|
||||
|
||||
return $decrypted;
|
||||
|
||||
}
|
||||
|
||||
public function postFopen($path,&$result) {
|
||||
if ( ! $result) {
|
||||
|
||||
public function postFopen( $path, &$result ){
|
||||
|
||||
if ( !$result ) {
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
$meta=stream_get_meta_data($result);
|
||||
if (self::isEncrypted($path)) {
|
||||
fclose($result);
|
||||
$result=fopen('crypt://'.$path, $meta['mode']);
|
||||
} elseif (self::shouldEncrypt($path) and $meta['mode']!='r' and $meta['mode']!='rb') {
|
||||
if (OC_Filesystem::file_exists($path) and OC_Filesystem::filesize($path)>0) {
|
||||
//first encrypt the target file so we don't end up with a half encrypted file
|
||||
OCP\Util::writeLog('files_encryption', 'Decrypting '.$path.' before writing', OCP\Util::DEBUG);
|
||||
$tmp=fopen('php://temp');
|
||||
OCP\Files::streamCopy($result, $tmp);
|
||||
fclose($result);
|
||||
OC_Filesystem::file_put_contents($path, $tmp);
|
||||
fclose($tmp);
|
||||
|
||||
// Reformat path for use with OC_FSV
|
||||
$path_split = explode( '/', $path );
|
||||
$path_f = implode( array_slice( $path_split, 3 ) );
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$meta = stream_get_meta_data( $result );
|
||||
|
||||
$view = new \OC_FilesystemView( '' );
|
||||
|
||||
$util = new Util( $view, \OCP\USER::getUser());
|
||||
|
||||
// If file is already encrypted, decrypt using crypto protocol
|
||||
if (
|
||||
Crypt::mode() == 'server'
|
||||
&& $util->isEncryptedPath( $path )
|
||||
) {
|
||||
|
||||
// Close the original encrypted file
|
||||
fclose( $result );
|
||||
|
||||
// Open the file using the crypto stream wrapper
|
||||
// protocol and let it do the decryption work instead
|
||||
$result = fopen( 'crypt://' . $path_f, $meta['mode'] );
|
||||
|
||||
|
||||
} elseif (
|
||||
self::shouldEncrypt( $path )
|
||||
and $meta ['mode'] != 'r'
|
||||
and $meta['mode'] != 'rb'
|
||||
) {
|
||||
// If the file is not yet encrypted, but should be
|
||||
// encrypted when it's saved (it's not read only)
|
||||
|
||||
// NOTE: this is the case for new files saved via WebDAV
|
||||
|
||||
if (
|
||||
$view->file_exists( $path )
|
||||
and $view->filesize( $path ) > 0
|
||||
) {
|
||||
$x = $view->file_get_contents( $path );
|
||||
|
||||
$tmp = tmpfile();
|
||||
|
||||
// // Make a temporary copy of the original file
|
||||
// \OCP\Files::streamCopy( $result, $tmp );
|
||||
//
|
||||
// // Close the original stream, we'll return another one
|
||||
// fclose( $result );
|
||||
//
|
||||
// $view->file_put_contents( $path_f, $tmp );
|
||||
//
|
||||
// fclose( $tmp );
|
||||
|
||||
}
|
||||
$result=fopen('crypt://'.$path, $meta['mode']);
|
||||
|
||||
$result = fopen( 'crypt://'.$path_f, $meta['mode'] );
|
||||
|
||||
}
|
||||
|
||||
// Re-enable the proxy
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function postGetMimeType($path, $mime) {
|
||||
if (self::isEncrypted($path)) {
|
||||
$mime=OCP\Files::getMimeType('crypt://'.$path, 'w');
|
||||
public function postGetMimeType($path,$mime){
|
||||
if( Crypt::isEncryptedContent($path)){
|
||||
$mime = \OCP\Files::getMimeType('crypt://'.$path,'w');
|
||||
}
|
||||
return $mime;
|
||||
}
|
||||
|
||||
public function postStat($path, $data) {
|
||||
if (self::isEncrypted($path)) {
|
||||
$cached=OC_FileCache_Cached::get($path, '');
|
||||
public function postStat($path,$data){
|
||||
if( Crypt::isEncryptedContent($path)){
|
||||
$cached= \OC_FileCache_Cached::get($path,'');
|
||||
$data['size']=$cached['size'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function postFileSize($path, $size) {
|
||||
if (self::isEncrypted($path)) {
|
||||
$cached=OC_FileCache_Cached::get($path, '');
|
||||
public function postFileSize($path,$size){
|
||||
if( Crypt::isEncryptedContent($path)){
|
||||
$cached = \OC_FileCache_Cached::get($path,'');
|
||||
return $cached['size'];
|
||||
} else {
|
||||
}else{
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
|
|
66
apps/files_encryption/lib/session.php
Normal file
66
apps/files_encryption/lib/session.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke
|
||||
* @copyright 2012 Sam Tuke samtuke@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;
|
||||
|
||||
/**
|
||||
* Class for handling encryption related session data
|
||||
*/
|
||||
|
||||
class Session {
|
||||
|
||||
/**
|
||||
* @brief Sets user id for session and triggers emit
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function setPrivateKey( $privateKey, $userId ) {
|
||||
|
||||
$_SESSION['privateKey'] = $privateKey;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets user id for session and triggers emit
|
||||
* @returns string $privateKey The user's plaintext private key
|
||||
*
|
||||
*/
|
||||
public function getPrivateKey( $userId ) {
|
||||
|
||||
if (
|
||||
isset( $_SESSION['privateKey'] )
|
||||
&& !empty( $_SESSION['privateKey'] )
|
||||
) {
|
||||
|
||||
return $_SESSION['privateKey'];
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
464
apps/files_encryption/lib/stream.php
Normal file
464
apps/files_encryption/lib/stream.php
Normal file
|
@ -0,0 +1,464 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Robin Appelman
|
||||
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
|
||||
* <icewind1991@gmail.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* transparently encrypted filestream
|
||||
*
|
||||
* you can use it as wrapper around an existing stream by setting CryptStream::$sourceStreams['foo']=array('path'=>$path,'stream'=>$stream)
|
||||
* and then fopen('crypt://streams/foo');
|
||||
*/
|
||||
|
||||
namespace OCA\Encryption;
|
||||
|
||||
/**
|
||||
* @brief Provides 'crypt://' stream wrapper protocol.
|
||||
* @note We use a stream wrapper because it is the most secure way to handle
|
||||
* decrypted content transfers. There is no safe way to decrypt the entire file
|
||||
* somewhere on the server, so we have to encrypt and decrypt blocks on the fly.
|
||||
* @note Paths used with this protocol MUST BE RELATIVE. Use URLs like:
|
||||
* crypt://filename, or crypt://subdirectory/filename, NOT
|
||||
* crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
|
||||
* [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
|
||||
* will not be accessible to other methods.
|
||||
* @note Data read and written must always be 8192 bytes long, as this is the
|
||||
* buffer size used internally by PHP. The encryption process makes the input
|
||||
* data longer, and input is chunked into smaller pieces in order to result in
|
||||
* a 8192 encrypted block size.
|
||||
*/
|
||||
class Stream {
|
||||
|
||||
public static $sourceStreams = array();
|
||||
|
||||
# TODO: make all below properties private again once unit testing is configured correctly
|
||||
public $rawPath; // The raw path received by stream_open
|
||||
public $path_f; // The raw path formatted to include username and data directory
|
||||
private $userId;
|
||||
private $handle; // Resource returned by fopen
|
||||
private $path;
|
||||
private $readBuffer; // For streams that dont support seeking
|
||||
private $meta = array(); // Header / meta for source stream
|
||||
private $count;
|
||||
private $writeCache;
|
||||
public $size;
|
||||
private $publicKey;
|
||||
private $keyfile;
|
||||
private $encKeyfile;
|
||||
private static $view; // a fsview object set to user dir
|
||||
private $rootView; // a fsview object set to '/'
|
||||
|
||||
public function stream_open( $path, $mode, $options, &$opened_path ) {
|
||||
|
||||
// Get access to filesystem via filesystemview object
|
||||
if ( !self::$view ) {
|
||||
|
||||
self::$view = new \OC_FilesystemView( $this->userId . '/' );
|
||||
|
||||
}
|
||||
|
||||
// Set rootview object if necessary
|
||||
if ( ! $this->rootView ) {
|
||||
|
||||
$this->rootView = new \OC_FilesystemView( $this->userId . '/' );
|
||||
|
||||
}
|
||||
|
||||
$this->userId = \OCP\User::getUser();
|
||||
|
||||
// Get the bare file path
|
||||
$path = str_replace( 'crypt://', '', $path );
|
||||
|
||||
$this->rawPath = $path;
|
||||
|
||||
$this->path_f = $this->userId . '/files/' . $path;
|
||||
|
||||
if (
|
||||
dirname( $path ) == 'streams'
|
||||
and isset( self::$sourceStreams[basename( $path )] )
|
||||
) {
|
||||
|
||||
// Is this just for unit testing purposes?
|
||||
|
||||
$this->handle = self::$sourceStreams[basename( $path )]['stream'];
|
||||
|
||||
$this->path = self::$sourceStreams[basename( $path )]['path'];
|
||||
|
||||
$this->size = self::$sourceStreams[basename( $path )]['size'];
|
||||
|
||||
} else {
|
||||
|
||||
if (
|
||||
$mode == 'w'
|
||||
or $mode == 'w+'
|
||||
or $mode == 'wb'
|
||||
or $mode == 'wb+'
|
||||
) {
|
||||
|
||||
$this->size = 0;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
|
||||
$this->size = self::$view->filesize( $this->path_f, $mode );
|
||||
|
||||
//$this->size = filesize( $path );
|
||||
|
||||
}
|
||||
|
||||
// Disable fileproxies so we can open the source file without recursive encryption
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
//$this->handle = fopen( $path, $mode );
|
||||
|
||||
$this->handle = self::$view->fopen( $this->path_f, $mode );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
if ( !is_resource( $this->handle ) ) {
|
||||
|
||||
\OCP\Util::writeLog( 'files_encryption', 'failed to open '.$path, \OCP\Util::ERROR );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( is_resource( $this->handle ) ) {
|
||||
|
||||
$this->meta = stream_get_meta_data( $this->handle );
|
||||
|
||||
}
|
||||
|
||||
return is_resource( $this->handle );
|
||||
|
||||
}
|
||||
|
||||
public function stream_seek( $offset, $whence = SEEK_SET ) {
|
||||
|
||||
$this->flush();
|
||||
|
||||
fseek( $this->handle, $offset, $whence );
|
||||
|
||||
}
|
||||
|
||||
public function stream_tell() {
|
||||
return ftell($this->handle);
|
||||
}
|
||||
|
||||
public function stream_read( $count ) {
|
||||
|
||||
$this->writeCache = '';
|
||||
|
||||
if ( $count != 8192 ) {
|
||||
|
||||
// $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 );
|
||||
|
||||
die();
|
||||
|
||||
}
|
||||
|
||||
// $pos = ftell( $this->handle );
|
||||
//
|
||||
// Get the data from the file handle
|
||||
$data = fread( $this->handle, 8192 );
|
||||
|
||||
if ( strlen( $data ) ) {
|
||||
|
||||
$this->getKey();
|
||||
|
||||
$result = Crypt::symmetricDecryptFileContent( $data, $this->keyfile );
|
||||
|
||||
} else {
|
||||
|
||||
$result = '';
|
||||
|
||||
}
|
||||
|
||||
// $length = $this->size - $pos;
|
||||
//
|
||||
// if ( $length < 8192 ) {
|
||||
//
|
||||
// $result = substr( $result, 0, $length );
|
||||
//
|
||||
// }
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypt and pad data ready for writting 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
|
||||
*/
|
||||
public function preWriteEncrypt( $plainData, $key ) {
|
||||
|
||||
// Encrypt data to 'catfile', which includes IV
|
||||
if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) {
|
||||
|
||||
return $encrypted;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the keyfile for the current file, generate one if necessary
|
||||
* @param bool $generate if true, a new key will be generated if none can be found
|
||||
* @return bool true on key found and set, false on key not found and new key generated and set
|
||||
*/
|
||||
public function getKey() {
|
||||
|
||||
// If a keyfile already exists for a file named identically to file to be written
|
||||
if ( self::$view->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) {
|
||||
|
||||
# TODO: add error handling for when file exists but no keyfile
|
||||
|
||||
// Fetch existing keyfile
|
||||
$this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->rawPath );
|
||||
|
||||
$this->getUser();
|
||||
|
||||
$session = new Session();
|
||||
|
||||
$privateKey = $session->getPrivateKey( $this->userId );
|
||||
|
||||
$this->keyfile = Crypt::keyDecrypt( $this->encKeyfile, $privateKey );
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getuser() {
|
||||
|
||||
// Only get the user again if it isn't already set
|
||||
if ( empty( $this->userId ) ) {
|
||||
|
||||
# TODO: Move this user call out of here - it belongs elsewhere
|
||||
$this->userId = \OCP\User::getUser();
|
||||
|
||||
}
|
||||
|
||||
# TODO: Add a method for getting the user in case OCP\User::
|
||||
# getUser() doesn't work (can that scenario ever occur?)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle plain data from the stream, and write it in 8192 byte blocks
|
||||
* @param string $data data to be written to disk
|
||||
* @note the data will be written to the path stored in the stream handle, set in stream_open()
|
||||
* @note $data is only ever be a maximum of 8192 bytes long. This is set by PHP internally. stream_write() is called multiple times in a loop on data larger than 8192 bytes
|
||||
* @note Because the encryption process used increases the length of $data, a writeCache is used to carry over data which would not fit in the required block size
|
||||
* @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read
|
||||
* @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek
|
||||
*/
|
||||
public function stream_write( $data ) {
|
||||
|
||||
// Disable the file proxies so that encryption is not automatically attempted when the file is written to disk - we are handling that separately here and we don't want to get into an infinite loop
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Get the length of the unencrypted data that we are handling
|
||||
$length = strlen( $data );
|
||||
|
||||
// So far this round, no data has been written
|
||||
$written = 0;
|
||||
|
||||
// Find out where we are up to in the writing of data to the file
|
||||
$pointer = ftell( $this->handle );
|
||||
|
||||
// Make sure the userId is set
|
||||
$this->getuser();
|
||||
|
||||
// Get / generate the keyfile for the file we're handling
|
||||
// If we're writing a new file (not overwriting an existing one), save the newly generated keyfile
|
||||
if ( ! $this->getKey() ) {
|
||||
|
||||
$this->keyfile = Crypt::generateKey();
|
||||
|
||||
$this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId );
|
||||
|
||||
$this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey );
|
||||
|
||||
// Save the new encrypted file key
|
||||
Keymanager::setFileKey( $this->rawPath, $this->encKeyfile, new \OC_FilesystemView( '/' ) );
|
||||
|
||||
# TODO: move this new OCFSV out of here some how, use DI
|
||||
|
||||
}
|
||||
|
||||
// If extra data is left over from the last round, make sure it is integrated into the next 6126 / 8192 block
|
||||
if ( $this->writeCache ) {
|
||||
|
||||
// Concat writeCache to start of $data
|
||||
$data = $this->writeCache . $data;
|
||||
|
||||
// Clear the write cache, ready for resuse - it has been flushed and its old contents processed
|
||||
$this->writeCache = '';
|
||||
|
||||
}
|
||||
//
|
||||
// // Make sure we always start on a block start
|
||||
if ( 0 != ( $pointer % 8192 ) ) { // if the current positoin of file indicator is not aligned to a 8192 byte block, fix it so that it is
|
||||
|
||||
// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR );
|
||||
//
|
||||
// $pointer = ftell( $this->handle );
|
||||
//
|
||||
// $unencryptedNewBlock = fread( $this->handle, 8192 );
|
||||
//
|
||||
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
|
||||
//
|
||||
// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->keyfile );
|
||||
//
|
||||
// $x = substr( $block, 0, $currentPos % 8192 );
|
||||
//
|
||||
// $data = $x . $data;
|
||||
//
|
||||
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
|
||||
//
|
||||
}
|
||||
|
||||
// $currentPos = ftell( $this->handle );
|
||||
|
||||
// // While there still remains somed data to be processed & written
|
||||
while( strlen( $data ) > 0 ) {
|
||||
//
|
||||
// // Remaining length for this iteration, not of the entire file (may be greater than 8192 bytes)
|
||||
// $remainingLength = strlen( $data );
|
||||
//
|
||||
// // If data remaining to be written is less than the size of 1 6126 byte block
|
||||
if ( strlen( $data ) < 6126 ) {
|
||||
|
||||
// Set writeCache to contents of $data
|
||||
// The writeCache will be carried over to the next write round, and added to the start of $data to ensure that written blocks are always the correct length. If there is still data in writeCache after the writing round has finished, then the data will be written to disk by $this->flush().
|
||||
$this->writeCache = $data;
|
||||
|
||||
// Clear $data ready for next round
|
||||
$data = '';
|
||||
//
|
||||
} else {
|
||||
|
||||
// Read the chunk from the start of $data
|
||||
$chunk = substr( $data, 0, 6126 );
|
||||
|
||||
$encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile );
|
||||
|
||||
// Write the data chunk to disk. This will be addended to the last data chunk if the file being handled totals more than 6126 bytes
|
||||
fwrite( $this->handle, $encrypted );
|
||||
|
||||
$writtenLen = strlen( $encrypted );
|
||||
//fseek( $this->handle, $writtenLen, SEEK_CUR );
|
||||
|
||||
// Remove the chunk we just processed from $data, leaving only unprocessed data in $data var, for handling on the next round
|
||||
$data = substr( $data, 6126 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->size = max( $this->size, $pointer + $length );
|
||||
|
||||
return $length;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function stream_set_option($option,$arg1,$arg2) {
|
||||
switch($option) {
|
||||
case STREAM_OPTION_BLOCKING:
|
||||
stream_set_blocking($this->handle,$arg1);
|
||||
break;
|
||||
case STREAM_OPTION_READ_TIMEOUT:
|
||||
stream_set_timeout($this->handle,$arg1,$arg2);
|
||||
break;
|
||||
case STREAM_OPTION_WRITE_BUFFER:
|
||||
stream_set_write_buffer($this->handle,$arg1,$arg2);
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_stat() {
|
||||
return fstat($this->handle);
|
||||
}
|
||||
|
||||
public function stream_lock($mode) {
|
||||
flock($this->handle,$mode);
|
||||
}
|
||||
|
||||
public function stream_flush() {
|
||||
|
||||
return fflush($this->handle); // Not a typo: http://php.net/manual/en/function.fflush.php
|
||||
|
||||
}
|
||||
|
||||
public function stream_eof() {
|
||||
return feof($this->handle);
|
||||
}
|
||||
|
||||
private function flush() {
|
||||
|
||||
if ( $this->writeCache ) {
|
||||
|
||||
// Set keyfile property for file in question
|
||||
$this->getKey();
|
||||
|
||||
$encrypted = $this->preWriteEncrypt( $this->writeCache, $this->keyfile );
|
||||
|
||||
fwrite( $this->handle, $encrypted );
|
||||
|
||||
$this->writeCache = '';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function stream_close() {
|
||||
|
||||
$this->flush();
|
||||
|
||||
if (
|
||||
$this->meta['mode']!='r'
|
||||
and $this->meta['mode']!='rb'
|
||||
) {
|
||||
|
||||
\OC_FileCache::put( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' );
|
||||
|
||||
}
|
||||
|
||||
return fclose( $this->handle );
|
||||
|
||||
}
|
||||
|
||||
}
|
330
apps/files_encryption/lib/util.php
Normal file
330
apps/files_encryption/lib/util.php
Normal file
|
@ -0,0 +1,330 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Sam Tuke, Frank Karlitschek
|
||||
* @copyright 2012 Sam Tuke samtuke@owncloud.com,
|
||||
* Frank Karlitschek frank@owncloud.org
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Todo:
|
||||
// - Crypt/decrypt button in the userinterface
|
||||
// - Setting if crypto should be on by default
|
||||
// - Add a setting "Don´t encrypt files larger than xx because of performance reasons"
|
||||
// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is encrypted (.encrypted extension)
|
||||
// - Don't use a password directly as encryption key. but a key which is stored on the server and encrypted with the user password. -> password change faster
|
||||
// - IMPORTANT! Check if the block lenght of the encrypted data stays the same
|
||||
|
||||
namespace OCA\Encryption;
|
||||
|
||||
/**
|
||||
* @brief Class for utilities relating to encrypted file storage system
|
||||
* @param $view OC_FilesystemView object, expected to have OC '/' as root path
|
||||
* @param $client flag indicating status of client side encryption. Currently
|
||||
* unused, likely to become obsolete shortly
|
||||
*/
|
||||
|
||||
class Util {
|
||||
|
||||
|
||||
# Web UI:
|
||||
|
||||
## DONE: files created via web ui are encrypted
|
||||
## DONE: file created & encrypted via web ui are readable in web ui
|
||||
## DONE: file created & encrypted via web ui are readable via webdav
|
||||
|
||||
|
||||
# WebDAV:
|
||||
|
||||
## DONE: new data filled files added via webdav get encrypted
|
||||
## DONE: new data filled files added via webdav are readable via webdav
|
||||
## DONE: reading unencrypted files when encryption is enabled works via webdav
|
||||
## DONE: files created & encrypted via web ui are readable via webdav
|
||||
|
||||
|
||||
# Legacy support:
|
||||
|
||||
## DONE: add method to check if file is encrypted using new system
|
||||
## DONE: add method to check if file is encrypted using old system
|
||||
## DONE: add method to fetch legacy key
|
||||
## DONE: add method to decrypt legacy encrypted data
|
||||
|
||||
## TODO: add method to encrypt all user files using new system
|
||||
## TODO: add method to decrypt all user files using new system
|
||||
## TODO: add method to encrypt all user files using old system
|
||||
## TODO: add method to decrypt all user files using old system
|
||||
|
||||
|
||||
# Admin UI:
|
||||
|
||||
## DONE: changing user password also changes encryption passphrase
|
||||
|
||||
## TODO: add support for optional recovery in case of lost passphrase / keys
|
||||
## TODO: add admin optional required long passphrase for users
|
||||
## TODO: add UI buttons for encrypt / decrypt everything
|
||||
## TODO: implement flag system to allow user to specify encryption by folder, subfolder, etc.
|
||||
|
||||
|
||||
# Sharing:
|
||||
|
||||
## TODO: add support for encrypting to multiple public keys
|
||||
## TODO: add support for decrypting to multiple private keys
|
||||
|
||||
|
||||
# Integration testing:
|
||||
|
||||
## TODO: test new encryption with webdav
|
||||
## TODO: test new encryption with versioning
|
||||
## TODO: test new encryption with sharing
|
||||
## TODO: test new encryption with proxies
|
||||
|
||||
|
||||
private $view; // OC_FilesystemView object for filesystem operations
|
||||
private $pwd; // User Password
|
||||
private $client; // Client side encryption mode flag
|
||||
private $publicKeyDir; // Directory containing all public user keys
|
||||
private $encryptionDir; // Directory containing user's files_encryption
|
||||
private $keyfilesPath; // Directory containing user's keyfiles
|
||||
private $publicKeyPath; // Path to user's public key
|
||||
private $privateKeyPath; // Path to user's private key
|
||||
|
||||
public function __construct( \OC_FilesystemView $view, $userId, $client = false ) {
|
||||
|
||||
$this->view = $view;
|
||||
$this->userId = $userId;
|
||||
$this->client = $client;
|
||||
$this->publicKeyDir = '/' . 'public-keys';
|
||||
$this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
|
||||
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
|
||||
$this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
|
||||
$this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
|
||||
|
||||
}
|
||||
|
||||
public function ready() {
|
||||
|
||||
if(
|
||||
!$this->view->file_exists( $this->keyfilesPath )
|
||||
or !$this->view->file_exists( $this->publicKeyPath )
|
||||
or !$this->view->file_exists( $this->privateKeyPath )
|
||||
) {
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets up user folders and keys for serverside encryption
|
||||
* @param $passphrase passphrase to encrypt server-stored private key with
|
||||
*/
|
||||
public function setupServerSide( $passphrase = null ) {
|
||||
|
||||
// Create shared public key directory
|
||||
if( !$this->view->file_exists( $this->publicKeyDir ) ) {
|
||||
|
||||
$this->view->mkdir( $this->publicKeyDir );
|
||||
|
||||
}
|
||||
|
||||
// Create encryption app directory
|
||||
if( !$this->view->file_exists( $this->encryptionDir ) ) {
|
||||
|
||||
$this->view->mkdir( $this->encryptionDir );
|
||||
|
||||
}
|
||||
|
||||
// Create mirrored keyfile directory
|
||||
if( !$this->view->file_exists( $this->keyfilesPath ) ) {
|
||||
|
||||
$this->view->mkdir( $this->keyfilesPath );
|
||||
|
||||
}
|
||||
|
||||
// Create user keypair
|
||||
if (
|
||||
!$this->view->file_exists( $this->publicKeyPath )
|
||||
or !$this->view->file_exists( $this->privateKeyPath )
|
||||
) {
|
||||
|
||||
// Generate keypair
|
||||
$keypair = Crypt::createKeypair();
|
||||
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Save public key
|
||||
$this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] );
|
||||
|
||||
// Encrypt private key with user pwd as passphrase
|
||||
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase );
|
||||
|
||||
// Save private key
|
||||
$this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function findFiles( $directory, $type = 'plain' ) {
|
||||
|
||||
# TODO: test finding non plain content
|
||||
|
||||
if ( $handle = $this->view->opendir( $directory ) ) {
|
||||
|
||||
while ( false !== ( $file = readdir( $handle ) ) ) {
|
||||
|
||||
if (
|
||||
$file != "."
|
||||
&& $file != ".."
|
||||
) {
|
||||
|
||||
$filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file );
|
||||
|
||||
var_dump($filePath);
|
||||
|
||||
if ( $this->view->is_dir( $filePath ) ) {
|
||||
|
||||
$this->findFiles( $filePath );
|
||||
|
||||
} elseif ( $this->view->is_file( $filePath ) ) {
|
||||
|
||||
if ( $type == 'plain' ) {
|
||||
|
||||
$this->files[] = array( 'name' => $file, 'path' => $filePath );
|
||||
|
||||
} elseif ( $type == 'encrypted' ) {
|
||||
|
||||
if ( Crypt::isEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) {
|
||||
|
||||
$this->files[] = array( 'name' => $file, 'path' => $filePath );
|
||||
|
||||
}
|
||||
|
||||
} elseif ( $type == 'legacy' ) {
|
||||
|
||||
if ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) {
|
||||
|
||||
$this->files[] = array( 'name' => $file, 'path' => $filePath );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( !empty( $this->files ) ) {
|
||||
|
||||
return $this->files;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a given path identifies an encrypted file
|
||||
* @return true / false
|
||||
*/
|
||||
public function isEncryptedPath( $path ) {
|
||||
|
||||
// Disable encryption proxy so data retreived is in its
|
||||
// original form
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$data = $this->view->file_get_contents( $path );
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
return Crypt::isEncryptedContent( $data );
|
||||
|
||||
}
|
||||
|
||||
public function encryptAll( $directory ) {
|
||||
|
||||
$plainFiles = $this->findFiles( $this->view, 'plain' );
|
||||
|
||||
if ( $this->encryptFiles( $plainFiles ) ) {
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getPath( $pathName ) {
|
||||
|
||||
switch ( $pathName ) {
|
||||
|
||||
case 'publicKeyDir':
|
||||
|
||||
return $this->publicKeyDir;
|
||||
|
||||
break;
|
||||
|
||||
case 'encryptionDir':
|
||||
|
||||
return $this->encryptionDir;
|
||||
|
||||
break;
|
||||
|
||||
case 'keyfilesPath':
|
||||
|
||||
return $this->keyfilesPath;
|
||||
|
||||
break;
|
||||
|
||||
case 'publicKeyPath':
|
||||
|
||||
return $this->publicKeyPath;
|
||||
|
||||
break;
|
||||
|
||||
case 'privateKeyPath':
|
||||
|
||||
return $this->privateKeyPath;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
29
apps/files_encryption/settings-personal.php
Normal file
29
apps/files_encryption/settings-personal.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
$sysEncMode = \OC_Appconfig::getValue('files_encryption', 'mode', 'none');
|
||||
|
||||
if ($sysEncMode == 'user') {
|
||||
|
||||
$tmpl = new OCP\Template( 'files_encryption', 'settings-personal');
|
||||
|
||||
$query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" );
|
||||
$result = $query->execute(array(\OCP\User::getUser()));
|
||||
|
||||
if ($row = $result->fetchRow()){
|
||||
$mode = $row['mode'];
|
||||
} else {
|
||||
$mode = 'none';
|
||||
}
|
||||
|
||||
OCP\Util::addscript('files_encryption','settings-personal');
|
||||
$tmpl->assign('encryption_mode', $mode);
|
||||
return $tmpl->fetchPage();
|
||||
}
|
||||
|
||||
return null;
|
|
@ -6,17 +6,16 @@
|
|||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
OC_Util::checkAdminUser();
|
||||
\OC_Util::checkAdminUser();
|
||||
|
||||
$tmpl = new OCP\Template( 'files_encryption', 'settings');
|
||||
$blackList=explode(',', OCP\Config::getAppValue('files_encryption',
|
||||
'type_blacklist',
|
||||
'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg'));
|
||||
$enabled=(OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true')=='true');
|
||||
$tmpl->assign('blacklist', $blackList);
|
||||
$tmpl->assign('encryption_enabled', $enabled);
|
||||
$tmpl = new OCP\Template( 'files_encryption', 'settings' );
|
||||
|
||||
OCP\Util::addscript('files_encryption', 'settings');
|
||||
OCP\Util::addscript('core', 'multiselect');
|
||||
$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) );
|
||||
|
||||
$tmpl->assign( 'blacklist', $blackList );
|
||||
$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) );
|
||||
|
||||
\OCP\Util::addscript( 'files_encryption', 'settings' );
|
||||
\OCP\Util::addscript( 'core', 'multiselect' );
|
||||
|
||||
return $tmpl->fetchPage();
|
||||
|
|
45
apps/files_encryption/templates/settings-personal.php
Normal file
45
apps/files_encryption/templates/settings-personal.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<form id="encryption">
|
||||
<fieldset class="personalblock">
|
||||
<strong><?php echo $l->t('Choose encryption mode:'); ?></strong>
|
||||
<p>
|
||||
<input
|
||||
type="hidden"
|
||||
name="prev_encryption_mode"
|
||||
id="prev_encryption_mode"
|
||||
value="<?php echo $_['encryption_mode']; ?>"
|
||||
>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
value="client"
|
||||
id='client_encryption'
|
||||
style="width:20px;"
|
||||
<?php if ($_['encryption_mode'] == 'client') echo "checked='checked'"?>
|
||||
/>
|
||||
<?php echo $l->t('Client side encryption (most secure but makes it impossible to access your data from the web interface)'); ?>
|
||||
<br />
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
value="server"
|
||||
id='server_encryption'
|
||||
style="width:20px;" <?php if ($_['encryption_mode'] == 'server') echo "checked='checked'"?>
|
||||
/>
|
||||
<?php echo $l->t('Server side encryption (allows you to access your files from the web interface and the desktop client)'); ?>
|
||||
<br />
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
value="none"
|
||||
id='none_encryption'
|
||||
style="width:20px;"
|
||||
<?php if ($_['encryption_mode'] == 'none') echo "checked='checked'"?>
|
||||
/>
|
||||
<?php echo $l->t('None (no encryption at all)'); ?>
|
||||
<br/>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
|
@ -1,14 +1,79 @@
|
|||
<form id="calendar">
|
||||
<form id="encryption">
|
||||
<fieldset class="personalblock">
|
||||
<legend><strong><?php echo $l->t('Encryption');?></strong></legend>
|
||||
<input type='checkbox'<?php if ($_['encryption_enabled']): ?> checked="checked"<?php endif; ?>
|
||||
id='enable_encryption' />
|
||||
<label for='enable_encryption'><?php echo $l->t('Enable Encryption')?></label><br />
|
||||
<select id='encryption_blacklist' title="<?php echo $l->t('None')?>" multiple="multiple">
|
||||
<?php foreach ($_['blacklist'] as $type): ?>
|
||||
<option selected="selected" value="<?php echo $type;?>"><?php echo $type;?></option>
|
||||
|
||||
<strong>
|
||||
<?php echo $l->t('Choose encryption mode:'); ?>
|
||||
</strong>
|
||||
|
||||
<p>
|
||||
<i>
|
||||
<?php echo $l->t('Important: Once you selected an encryption mode there is no way to change it back'); ?>
|
||||
</i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
id="client_encryption"
|
||||
value="client"
|
||||
style="width:20px;"
|
||||
<?php if ($_['encryption_mode'] == 'client') echo "checked='checked'"; if ($_['encryption_mode'] != 'none') echo "DISABLED"?>
|
||||
/>
|
||||
|
||||
<?php echo $l->t("Client side encryption (most secure but makes it impossible to access your data from the web interface)"); ?>
|
||||
<br />
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
id="server_encryption"
|
||||
value="server"
|
||||
style="width:20px;"
|
||||
<?php if ($_['encryption_mode'] == 'server') echo "checked='checked'"; if ($_['encryption_mode'] != 'none') echo "DISABLED"?>
|
||||
/>
|
||||
|
||||
<?php echo $l->t('Server side encryption (allows you to access your files from the web interface and the desktop client)'); ?>
|
||||
<br />
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
id="user_encryption"
|
||||
value="user"
|
||||
style="width:20px;"
|
||||
<?php if ($_['encryption_mode'] == 'user') echo "checked='checked'"; if ($_['encryption_mode'] != 'none') echo "DISABLED"?>
|
||||
/>
|
||||
|
||||
<?php echo $l->t('User specific (let the user decide)'); ?>
|
||||
<br/>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="encryption_mode"
|
||||
id="none_encryption"
|
||||
value="none"
|
||||
style="width:20px;"
|
||||
<?php if ($_['encryption_mode'] == 'none') echo "checked='checked'"; if ($_['encryption_mode'] != 'none') echo "DISABLED"?>
|
||||
/>
|
||||
|
||||
<?php echo $l->t('None (no encryption at all)'); ?>
|
||||
<br/>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php echo $l->t('Encryption'); ?></strong>
|
||||
|
||||
<?php echo $l->t("Exclude the following file types from encryption"); ?>
|
||||
|
||||
<select
|
||||
id='encryption_blacklist'
|
||||
title="<?php echo $l->t('None')?>"
|
||||
multiple="multiple">
|
||||
<?php foreach($_["blacklist"] as $type): ?>
|
||||
<option selected="selected" value="<?php echo $type;?>"> <?php echo $type;?> </option>
|
||||
<?php endforeach;?>
|
||||
</select><br />
|
||||
<?php echo $l->t('Exclude the following file types from encryption'); ?>
|
||||
</select>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
|
667
apps/files_encryption/test/crypt.php
Executable file
667
apps/files_encryption/test/crypt.php
Executable file
|
@ -0,0 +1,667 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>, and
|
||||
* Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
//require_once "PHPUnit/Framework/TestCase.php";
|
||||
require_once realpath( dirname(__FILE__).'/../../../3rdparty/Crypt_Blowfish/Blowfish.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../../../lib/base.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
// This has to go here because otherwise session errors arise, and the private
|
||||
// encryption key needs to be saved in the session
|
||||
\OC_User::login( 'admin', 'admin' );
|
||||
|
||||
/**
|
||||
* @note It would be better to use Mockery here for mocking out the session
|
||||
* handling process, and isolate calls to session class and data from the unit
|
||||
* tests relating to them (stream etc.). However getting mockery to work and
|
||||
* overload classes whilst also using the OC autoloader is difficult due to
|
||||
* load order Pear errors.
|
||||
*/
|
||||
|
||||
class Test_Crypt extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function setUp() {
|
||||
|
||||
// set content for encrypting / decrypting in tests
|
||||
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
||||
$this->dataShort = 'hats';
|
||||
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
$this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
|
||||
$this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
|
||||
$this->randomKey = Encryption\Crypt::generateKey();
|
||||
|
||||
$keypair = Encryption\Crypt::createKeypair();
|
||||
$this->genPublicKey = $keypair['publicKey'];
|
||||
$this->genPrivateKey = $keypair['privateKey'];
|
||||
|
||||
$this->view = new \OC_FilesystemView( '/' );
|
||||
|
||||
\OC_User::setUserId( 'admin' );
|
||||
$this->userId = 'admin';
|
||||
$this->pass = 'admin';
|
||||
|
||||
\OC_Filesystem::init( '/' );
|
||||
\OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => \OC_User::getHome($this->userId)), '/' );
|
||||
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
|
||||
}
|
||||
|
||||
function testGenerateKey() {
|
||||
|
||||
# TODO: use more accurate (larger) string length for test confirmation
|
||||
|
||||
$key = Encryption\Crypt::generateKey();
|
||||
|
||||
$this->assertTrue( strlen( $key ) > 16 );
|
||||
|
||||
}
|
||||
|
||||
function testGenerateIv() {
|
||||
|
||||
$iv = Encryption\Crypt::generateIv();
|
||||
|
||||
$this->assertEquals( 16, strlen( $iv ) );
|
||||
|
||||
return $iv;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testGenerateIv
|
||||
*/
|
||||
function testConcatIv( $iv ) {
|
||||
|
||||
$catFile = Encryption\Crypt::concatIv( $this->dataLong, $iv );
|
||||
|
||||
// Fetch encryption metadata from end of file
|
||||
$meta = substr( $catFile, -22 );
|
||||
|
||||
$identifier = substr( $meta, 0, 6);
|
||||
|
||||
// Fetch IV from end of file
|
||||
$foundIv = substr( $meta, 6 );
|
||||
|
||||
$this->assertEquals( '00iv00', $identifier );
|
||||
|
||||
$this->assertEquals( $iv, $foundIv );
|
||||
|
||||
// Remove IV and IV identifier text to expose encrypted content
|
||||
$data = substr( $catFile, 0, -22 );
|
||||
|
||||
$this->assertEquals( $this->dataLong, $data );
|
||||
|
||||
return array(
|
||||
'iv' => $iv
|
||||
, 'catfile' => $catFile
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testConcatIv
|
||||
*/
|
||||
function testSplitIv( $testConcatIv ) {
|
||||
|
||||
// Split catfile into components
|
||||
$splitCatfile = Encryption\Crypt::splitIv( $testConcatIv['catfile'] );
|
||||
|
||||
// Check that original IV and split IV match
|
||||
$this->assertEquals( $testConcatIv['iv'], $splitCatfile['iv'] );
|
||||
|
||||
// Check that original data and split data match
|
||||
$this->assertEquals( $this->dataLong, $splitCatfile['encrypted'] );
|
||||
|
||||
}
|
||||
|
||||
function testAddPadding() {
|
||||
|
||||
$padded = Encryption\Crypt::addPadding( $this->dataLong );
|
||||
|
||||
$padding = substr( $padded, -2 );
|
||||
|
||||
$this->assertEquals( 'xx' , $padding );
|
||||
|
||||
return $padded;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAddPadding
|
||||
*/
|
||||
function testRemovePadding( $padded ) {
|
||||
|
||||
$noPadding = Encryption\Crypt::RemovePadding( $padded );
|
||||
|
||||
$this->assertEquals( $this->dataLong, $noPadding );
|
||||
|
||||
}
|
||||
|
||||
function testEncrypt() {
|
||||
|
||||
$random = openssl_random_pseudo_bytes( 13 );
|
||||
|
||||
$iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht
|
||||
|
||||
$crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' );
|
||||
|
||||
$this->assertNotEquals( $this->dataUrl, $crypted );
|
||||
|
||||
}
|
||||
|
||||
function testDecrypt() {
|
||||
|
||||
$random = openssl_random_pseudo_bytes( 13 );
|
||||
|
||||
$iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht
|
||||
|
||||
$crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' );
|
||||
|
||||
$decrypt = Encryption\Crypt::decrypt( $crypted, $iv, 'hat' );
|
||||
|
||||
$this->assertEquals( $this->dataUrl, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
function testSymmetricEncryptFileContent() {
|
||||
|
||||
# TODO: search in keyfile for actual content as IV will ensure this test always passes
|
||||
|
||||
$crypted = Encryption\Crypt::symmetricEncryptFileContent( $this->dataShort, 'hat' );
|
||||
|
||||
$this->assertNotEquals( $this->dataShort, $crypted );
|
||||
|
||||
|
||||
$decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted, 'hat' );
|
||||
|
||||
$this->assertEquals( $this->dataShort, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
// These aren't used for now
|
||||
// function testSymmetricBlockEncryptShortFileContent() {
|
||||
//
|
||||
// $crypted = Encryption\Crypt::symmetricBlockEncryptFileContent( $this->dataShort, $this->randomKey );
|
||||
//
|
||||
// $this->assertNotEquals( $this->dataShort, $crypted );
|
||||
//
|
||||
//
|
||||
// $decrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $crypted, $this->randomKey );
|
||||
//
|
||||
// $this->assertEquals( $this->dataShort, $decrypt );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function testSymmetricBlockEncryptLongFileContent() {
|
||||
//
|
||||
// $crypted = Encryption\Crypt::symmetricBlockEncryptFileContent( $this->dataLong, $this->randomKey );
|
||||
//
|
||||
// $this->assertNotEquals( $this->dataLong, $crypted );
|
||||
//
|
||||
//
|
||||
// $decrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $crypted, $this->randomKey );
|
||||
//
|
||||
// $this->assertEquals( $this->dataLong, $decrypt );
|
||||
//
|
||||
// }
|
||||
|
||||
function testSymmetricStreamEncryptShortFileContent() {
|
||||
|
||||
$filename = 'tmp-'.time();
|
||||
|
||||
$cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort );
|
||||
|
||||
// Test that data was successfully written
|
||||
$this->assertTrue( is_int( $cryptedFile ) );
|
||||
|
||||
|
||||
// Get file contents without using any wrapper to get it's actual contents on disk
|
||||
$retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename );
|
||||
|
||||
// Check that the file was encrypted before being written to disk
|
||||
$this->assertNotEquals( $this->dataShort, $retreivedCryptedFile );
|
||||
|
||||
// Get private key
|
||||
$encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
||||
|
||||
$decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
|
||||
|
||||
|
||||
// Get keyfile
|
||||
$encryptedKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename );
|
||||
|
||||
$decryptedKeyfile = Encryption\Crypt::keyDecrypt( $encryptedKeyfile, $decryptedPrivateKey );
|
||||
|
||||
|
||||
// Manually decrypt
|
||||
$manualDecrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $retreivedCryptedFile, $decryptedKeyfile );
|
||||
|
||||
// Check that decrypted data matches
|
||||
$this->assertEquals( $this->dataShort, $manualDecrypt );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test that data that is written by the crypto stream wrapper
|
||||
* @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read
|
||||
* @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual
|
||||
* reassembly of its data
|
||||
*/
|
||||
function testSymmetricStreamEncryptLongFileContent() {
|
||||
|
||||
// Generate a a random filename
|
||||
$filename = 'tmp-'.time();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong.$this->dataLong );
|
||||
|
||||
// Test that data was successfully written
|
||||
$this->assertTrue( is_int( $cryptedFile ) );
|
||||
|
||||
// Get file contents without using any wrapper to get it's actual contents on disk
|
||||
$retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename );
|
||||
|
||||
// echo "\n\n\$retreivedCryptedFile = $retreivedCryptedFile\n\n";
|
||||
|
||||
// Check that the file was encrypted before being written to disk
|
||||
$this->assertNotEquals( $this->dataLong.$this->dataLong, $retreivedCryptedFile );
|
||||
|
||||
// Manuallly split saved file into separate IVs and encrypted chunks
|
||||
$r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
//print_r($r);
|
||||
|
||||
// Join IVs and their respective data chunks
|
||||
$e = array( $r[0].$r[1], $r[2].$r[3], $r[4].$r[5], $r[6].$r[7], $r[8].$r[9], $r[10].$r[11], $r[12].$r[13] );//.$r[11], $r[12].$r[13], $r[14] );
|
||||
|
||||
//print_r($e);
|
||||
|
||||
|
||||
// Get private key
|
||||
$encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
||||
|
||||
$decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass );
|
||||
|
||||
|
||||
// Get keyfile
|
||||
$encryptedKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename );
|
||||
|
||||
$decryptedKeyfile = Encryption\Crypt::keyDecrypt( $encryptedKeyfile, $decryptedPrivateKey );
|
||||
|
||||
|
||||
// Set var for reassembling decrypted content
|
||||
$decrypt = '';
|
||||
|
||||
// Manually decrypt chunk
|
||||
foreach ($e as $e) {
|
||||
|
||||
// echo "\n\$e = $e";
|
||||
|
||||
$chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $e, $decryptedKeyfile );
|
||||
|
||||
// Assemble decrypted chunks
|
||||
$decrypt .= $chunkDecrypt;
|
||||
|
||||
// echo "\n\$chunkDecrypt = $chunkDecrypt";
|
||||
|
||||
}
|
||||
|
||||
// echo "\n\$decrypt = $decrypt";
|
||||
|
||||
$this->assertEquals( $this->dataLong.$this->dataLong, $decrypt );
|
||||
|
||||
// Teardown
|
||||
|
||||
$this->view->unlink( $filename );
|
||||
|
||||
Encryption\Keymanager::deleteFileKey( $filename );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test that data that is read by the crypto stream wrapper
|
||||
*/
|
||||
function testSymmetricStreamDecryptShortFileContent() {
|
||||
|
||||
$filename = 'tmp-'.time();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort );
|
||||
|
||||
// Test that data was successfully written
|
||||
$this->assertTrue( is_int( $cryptedFile ) );
|
||||
|
||||
|
||||
// Get file contents without using any wrapper to get it's actual contents on disk
|
||||
$retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename );
|
||||
|
||||
$decrypt = file_get_contents( 'crypt://' . $filename );
|
||||
|
||||
$this->assertEquals( $this->dataShort, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
function testSymmetricStreamDecryptLongFileContent() {
|
||||
|
||||
$filename = 'tmp-'.time();
|
||||
|
||||
// Save long data as encrypted file using stream wrapper
|
||||
$cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong );
|
||||
|
||||
// Test that data was successfully written
|
||||
$this->assertTrue( is_int( $cryptedFile ) );
|
||||
|
||||
|
||||
// Get file contents without using any wrapper to get it's actual contents on disk
|
||||
$retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename );
|
||||
|
||||
$decrypt = file_get_contents( 'crypt://' . $filename );
|
||||
|
||||
$this->assertEquals( $this->dataLong, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
// Is this test still necessary?
|
||||
// function testSymmetricBlockStreamDecryptFileContent() {
|
||||
//
|
||||
// \OC_User::setUserId( 'admin' );
|
||||
//
|
||||
// // Disable encryption proxy to prevent unwanted en/decryption
|
||||
// \OC_FileProxy::$enabled = false;
|
||||
//
|
||||
// $cryptedFile = file_put_contents( 'crypt://' . '/blockEncrypt', $this->dataUrl );
|
||||
//
|
||||
// // Disable encryption proxy to prevent unwanted en/decryption
|
||||
// \OC_FileProxy::$enabled = false;
|
||||
//
|
||||
// echo "\n\n\$cryptedFile = " . $this->view->file_get_contents( '/blockEncrypt' );
|
||||
//
|
||||
// $retreivedCryptedFile = file_get_contents( 'crypt://' . '/blockEncrypt' );
|
||||
//
|
||||
// $this->assertEquals( $this->dataUrl, $retreivedCryptedFile );
|
||||
//
|
||||
// \OC_FileProxy::$enabled = false;
|
||||
//
|
||||
// }
|
||||
|
||||
function testSymmetricEncryptFileContentKeyfile() {
|
||||
|
||||
# TODO: search in keyfile for actual content as IV will ensure this test always passes
|
||||
|
||||
$crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl );
|
||||
|
||||
$this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] );
|
||||
|
||||
|
||||
$decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted['encrypted'], $crypted['key'] );
|
||||
|
||||
$this->assertEquals( $this->dataUrl, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
function testIsEncryptedContent() {
|
||||
|
||||
$this->assertFalse( Encryption\Crypt::isEncryptedContent( $this->dataUrl ) );
|
||||
|
||||
$this->assertFalse( Encryption\Crypt::isEncryptedContent( $this->legacyEncryptedData ) );
|
||||
|
||||
$keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' );
|
||||
|
||||
$this->assertTrue( Encryption\Crypt::isEncryptedContent( $keyfileContent ) );
|
||||
|
||||
}
|
||||
|
||||
function testMultiKeyEncrypt() {
|
||||
|
||||
# TODO: search in keyfile for actual content as IV will ensure this test always passes
|
||||
|
||||
$pair1 = Encryption\Crypt::createKeypair();
|
||||
|
||||
$this->assertEquals( 2, count( $pair1 ) );
|
||||
|
||||
$this->assertTrue( strlen( $pair1['publicKey'] ) > 1 );
|
||||
|
||||
$this->assertTrue( strlen( $pair1['privateKey'] ) > 1 );
|
||||
|
||||
|
||||
$crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataUrl, array( $pair1['publicKey'] ) );
|
||||
|
||||
$this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] );
|
||||
|
||||
|
||||
$decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['encrypted'], $crypted['keys'][0], $pair1['privateKey'] );
|
||||
|
||||
$this->assertEquals( $this->dataUrl, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
function testKeyEncrypt() {
|
||||
|
||||
// Generate keypair
|
||||
$pair1 = Encryption\Crypt::createKeypair();
|
||||
|
||||
// Encrypt data
|
||||
$crypted = Encryption\Crypt::keyEncrypt( $this->dataUrl, $pair1['publicKey'] );
|
||||
|
||||
$this->assertNotEquals( $this->dataUrl, $crypted );
|
||||
|
||||
// Decrypt data
|
||||
$decrypt = Encryption\Crypt::keyDecrypt( $crypted, $pair1['privateKey'] );
|
||||
|
||||
$this->assertEquals( $this->dataUrl, $decrypt );
|
||||
|
||||
}
|
||||
|
||||
// What is the point of this test? It doesn't use keyEncryptKeyfile()
|
||||
function testKeyEncryptKeyfile() {
|
||||
|
||||
# TODO: Don't repeat encryption from previous tests, use PHPUnit test interdependency instead
|
||||
|
||||
// Generate keypair
|
||||
$pair1 = Encryption\Crypt::createKeypair();
|
||||
|
||||
// Encrypt plain data, generate keyfile & encrypted file
|
||||
$cryptedData = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl );
|
||||
|
||||
// Encrypt keyfile
|
||||
$cryptedKey = Encryption\Crypt::keyEncrypt( $cryptedData['key'], $pair1['publicKey'] );
|
||||
|
||||
// Decrypt keyfile
|
||||
$decryptKey = Encryption\Crypt::keyDecrypt( $cryptedKey, $pair1['privateKey'] );
|
||||
|
||||
// Decrypt encrypted file
|
||||
$decryptData = Encryption\Crypt::symmetricDecryptFileContent( $cryptedData['encrypted'], $decryptKey );
|
||||
|
||||
$this->assertEquals( $this->dataUrl, $decryptData );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test functionality of keyEncryptKeyfile() and
|
||||
* keyDecryptKeyfile()
|
||||
*/
|
||||
function testKeyDecryptKeyfile() {
|
||||
|
||||
$encrypted = Encryption\Crypt::keyEncryptKeyfile( $this->dataShort, $this->genPublicKey );
|
||||
|
||||
$this->assertNotEquals( $encrypted['data'], $this->dataShort );
|
||||
|
||||
$decrypted = Encryption\Crypt::keyDecryptKeyfile( $encrypted['data'], $encrypted['key'], $this->genPrivateKey );
|
||||
|
||||
$this->assertEquals( $decrypted, $this->dataShort );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief test encryption using legacy blowfish method
|
||||
*/
|
||||
function testLegacyEncryptShort() {
|
||||
|
||||
$crypted = Encryption\Crypt::legacyEncrypt( $this->dataShort, $this->pass );
|
||||
|
||||
$this->assertNotEquals( $this->dataShort, $crypted );
|
||||
|
||||
# TODO: search inencrypted text for actual content to ensure it
|
||||
# genuine transformation
|
||||
|
||||
return $crypted;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test decryption using legacy blowfish method
|
||||
* @depends testLegacyEncryptShort
|
||||
*/
|
||||
function testLegacyDecryptShort( $crypted ) {
|
||||
|
||||
$decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass );
|
||||
|
||||
$this->assertEquals( $this->dataShort, $decrypted );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test encryption using legacy blowfish method
|
||||
*/
|
||||
function testLegacyEncryptLong() {
|
||||
|
||||
$crypted = Encryption\Crypt::legacyEncrypt( $this->dataLong, $this->pass );
|
||||
|
||||
$this->assertNotEquals( $this->dataLong, $crypted );
|
||||
|
||||
# TODO: search inencrypted text for actual content to ensure it
|
||||
# genuine transformation
|
||||
|
||||
return $crypted;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test decryption using legacy blowfish method
|
||||
* @depends testLegacyEncryptLong
|
||||
*/
|
||||
function testLegacyDecryptLong( $crypted ) {
|
||||
|
||||
$decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass );
|
||||
|
||||
$this->assertEquals( $this->dataLong, $decrypted );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test generation of legacy encryption key
|
||||
* @depends testLegacyDecryptShort
|
||||
*/
|
||||
function testLegacyCreateKey() {
|
||||
|
||||
// Create encrypted key
|
||||
$encKey = Encryption\Crypt::legacyCreateKey( $this->pass );
|
||||
|
||||
// Decrypt key
|
||||
$key = Encryption\Crypt::legacyDecrypt( $encKey, $this->pass );
|
||||
|
||||
$this->assertTrue( is_numeric( $key ) );
|
||||
|
||||
// Check that key is correct length
|
||||
$this->assertEquals( 20, strlen( $key ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test decryption using legacy blowfish method
|
||||
* @depends testLegacyEncryptLong
|
||||
*/
|
||||
function testLegacyKeyRecryptKeyfileEncrypt( $crypted ) {
|
||||
|
||||
$recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, $this->genPublicKey, $this->pass );
|
||||
|
||||
$this->assertNotEquals( $this->dataLong, $recrypted['data'] );
|
||||
|
||||
return $recrypted;
|
||||
|
||||
# TODO: search inencrypted text for actual content to ensure it
|
||||
# genuine transformation
|
||||
|
||||
}
|
||||
|
||||
// function testEncryption(){
|
||||
//
|
||||
// $key=uniqid();
|
||||
// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
// $source=file_get_contents($file); //nice large text file
|
||||
// $encrypted=OC_Encryption\Crypt::encrypt($source,$key);
|
||||
// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
|
||||
// $decrypted=rtrim($decrypted, "\0");
|
||||
// $this->assertNotEquals($encrypted,$source);
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// $chunk=substr($source,0,8192);
|
||||
// $encrypted=OC_Encryption\Crypt::encrypt($chunk,$key);
|
||||
// $this->assertEqual(strlen($chunk),strlen($encrypted));
|
||||
// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
|
||||
// $decrypted=rtrim($decrypted, "\0");
|
||||
// $this->assertEqual($decrypted,$chunk);
|
||||
//
|
||||
// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key);
|
||||
// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key);
|
||||
// $this->assertNotEquals($encrypted,$source);
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// $tmpFileEncrypted=OCP\Files::tmpFile();
|
||||
// OC_Encryption\Crypt::encryptfile($file,$tmpFileEncrypted,$key);
|
||||
// $encrypted=file_get_contents($tmpFileEncrypted);
|
||||
// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key);
|
||||
// $this->assertNotEquals($encrypted,$source);
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// $tmpFileDecrypted=OCP\Files::tmpFile();
|
||||
// OC_Encryption\Crypt::decryptfile($tmpFileEncrypted,$tmpFileDecrypted,$key);
|
||||
// $decrypted=file_get_contents($tmpFileDecrypted);
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// $file=OC::$SERVERROOT.'/core/img/weather-clear.png';
|
||||
// $source=file_get_contents($file); //binary file
|
||||
// $encrypted=OC_Encryption\Crypt::encrypt($source,$key);
|
||||
// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
|
||||
// $decrypted=rtrim($decrypted, "\0");
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key);
|
||||
// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key);
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function testBinary(){
|
||||
// $key=uniqid();
|
||||
//
|
||||
// $file=__DIR__.'/binary';
|
||||
// $source=file_get_contents($file); //binary file
|
||||
// $encrypted=OC_Encryption\Crypt::encrypt($source,$key);
|
||||
// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key);
|
||||
//
|
||||
// $decrypted=rtrim($decrypted, "\0");
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
//
|
||||
// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key);
|
||||
// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key,strlen($source));
|
||||
// $this->assertEqual($decrypted,$source);
|
||||
// }
|
||||
|
||||
}
|
132
apps/files_encryption/test/keymanager.php
Normal file
132
apps/files_encryption/test/keymanager.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
//require_once "PHPUnit/Framework/TestCase.php";
|
||||
require_once realpath( dirname(__FILE__).'/../../../lib/base.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
// This has to go here because otherwise session errors arise, and the private
|
||||
// encryption key needs to be saved in the session
|
||||
\OC_User::login( 'admin', 'admin' );
|
||||
|
||||
class Test_Keymanager extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function setUp() {
|
||||
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// set content for encrypting / decrypting in tests
|
||||
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
||||
$this->dataShort = 'hats';
|
||||
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
$this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
|
||||
$this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
|
||||
$this->randomKey = Encryption\Crypt::generateKey();
|
||||
|
||||
$keypair = Encryption\Crypt::createKeypair();
|
||||
$this->genPublicKey = $keypair['publicKey'];
|
||||
$this->genPrivateKey = $keypair['privateKey'];
|
||||
|
||||
$this->view = new \OC_FilesystemView( '/' );
|
||||
|
||||
\OC_User::setUserId( 'admin' );
|
||||
$this->userId = 'admin';
|
||||
$this->pass = 'admin';
|
||||
|
||||
\OC_Filesystem::init( '/' );
|
||||
\OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => \OC_User::getHome($this->userId)), '/' );
|
||||
|
||||
}
|
||||
|
||||
function tearDown(){
|
||||
|
||||
\OC_FileProxy::$enabled = true;
|
||||
|
||||
}
|
||||
|
||||
function testGetPrivateKey() {
|
||||
|
||||
$key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
||||
|
||||
// Will this length vary? Perhaps we should use a range instead
|
||||
$this->assertEquals( 2296, strlen( $key ) );
|
||||
|
||||
}
|
||||
|
||||
function testGetPublicKey() {
|
||||
|
||||
$key = Encryption\Keymanager::getPublicKey( $this->view, $this->userId );
|
||||
|
||||
$this->assertEquals( 451, strlen( $key ) );
|
||||
|
||||
$this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $key, 0, 26 ) );
|
||||
}
|
||||
|
||||
function testSetFileKey() {
|
||||
|
||||
# NOTE: This cannot be tested until we are able to break out
|
||||
# of the FileSystemView data directory root
|
||||
|
||||
// $key = Crypt::symmetricEncryptFileContentKeyfile( $this->data, 'hat' );
|
||||
//
|
||||
// $tmpPath = sys_get_temp_dir(). '/' . 'testSetFileKey';
|
||||
//
|
||||
// $view = new \OC_FilesystemView( '/tmp/' );
|
||||
//
|
||||
// //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' );
|
||||
//
|
||||
// Encryption\Keymanager::setFileKey( $tmpPath, $key['key'], $view );
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @depends testGetPrivateKey
|
||||
// */
|
||||
// function testGetPrivateKey_decrypt() {
|
||||
//
|
||||
// $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId );
|
||||
//
|
||||
// # TODO: replace call to Crypt with a mock object?
|
||||
// $decrypted = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->passphrase );
|
||||
//
|
||||
// $this->assertEquals( 1704, strlen( $decrypted ) );
|
||||
//
|
||||
// $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) );
|
||||
//
|
||||
// }
|
||||
|
||||
function testGetUserKeys() {
|
||||
|
||||
$keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId );
|
||||
|
||||
$this->assertEquals( 451, strlen( $keys['publicKey'] ) );
|
||||
$this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $keys['publicKey'], 0, 26 ) );
|
||||
$this->assertEquals( 2296, strlen( $keys['privateKey'] ) );
|
||||
|
||||
}
|
||||
|
||||
function testGetPublicKeys() {
|
||||
|
||||
# TODO: write me
|
||||
|
||||
}
|
||||
|
||||
function testGetFileKey() {
|
||||
|
||||
// Encryption\Keymanager::getFileKey( $this->view, $this->userId, $this->filePath );
|
||||
|
||||
}
|
||||
|
||||
}
|
BIN
apps/files_encryption/test/legacy-encrypted-text.txt
Normal file
BIN
apps/files_encryption/test/legacy-encrypted-text.txt
Normal file
Binary file not shown.
220
apps/files_encryption/test/proxy.php
Normal file
220
apps/files_encryption/test/proxy.php
Normal file
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>,
|
||||
* and Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
// require_once "PHPUnit/Framework/TestCase.php";
|
||||
// require_once realpath( dirname(__FILE__).'/../../../lib/base.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Generator.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/MockInterface.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Mock.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Container.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Configuration.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CompositeExpectation.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/ExpectationDirector.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Expectation.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Exception.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CountValidator/CountValidatorAbstract.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CountValidator/Exception.php' );
|
||||
// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CountValidator/Exact.php' );
|
||||
//
|
||||
// use \Mockery as m;
|
||||
// use OCA\Encryption;
|
||||
|
||||
// class Test_Util extends \PHPUnit_Framework_TestCase {
|
||||
//
|
||||
// public function setUp() {
|
||||
//
|
||||
// $this->proxy = new Encryption\Proxy();
|
||||
//
|
||||
// $this->tmpFileName = "tmpFile-".time();
|
||||
//
|
||||
// $this->privateKey = file_get_contents( realpath( dirname(__FILE__).'/data/admin.public.key' ) );
|
||||
// $this->publicKey = file_get_contents( realpath( dirname(__FILE__).'/data/admin.private.key' ) );
|
||||
// $this->encDataShort = file_get_contents( realpath( dirname(__FILE__).'/data/yoga-manchester-enc' ) );
|
||||
// $this->encDataShortKey = file_get_contents( realpath( dirname(__FILE__).'/data/yoga-manchester.key' ) );
|
||||
//
|
||||
// $this->dataShort = file_get_contents( realpath( dirname(__FILE__).'/data/yoga-manchester' ) );
|
||||
// $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
||||
// $this->longDataPath = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
//
|
||||
// $this->data1 = file_get_contents( realpath( dirname(__FILE__).'/../../../data/admin/files/enc-test.txt' ) );
|
||||
//
|
||||
// \OC_FileProxy::$enabled = false;
|
||||
// $this->Encdata1 = file_get_contents( realpath( dirname(__FILE__).'/../../../data/admin/files/enc-test.txt' ) );
|
||||
// \OC_FileProxy::$enabled = true;
|
||||
//
|
||||
// $this->userId = 'admin';
|
||||
// $this->pass = 'admin';
|
||||
//
|
||||
// $this->session = new Encryption\Session();
|
||||
//
|
||||
// $this->session->setPrivateKey(
|
||||
// '-----BEGIN PRIVATE KEY-----
|
||||
// MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDiH3EA4EpFA7Fx
|
||||
// s2dyyfL5jwXeYXrTqQJ6DqKgGn8VsbT3eu8R9KzM2XitVwZe8c8L52DvJ06o5vg0
|
||||
// GqPYxilFdOFJe/ggac5Tq8UmJiZS4EqYEMwxBIfIyWTxeGV06/0HOwnVAkqHMcBz
|
||||
// 64qldtgi5O8kZMEM2/gKBgU0kMLJzM+8oEWhL1+gsUWQhxd8cKLXypS6iWgqFJrz
|
||||
// f/X0hJsJR+gyYxNpahtnjzd/LxLAETrOMsl2tue+BAxmjbAM0aG0NEM0div+b59s
|
||||
// 2uz/iWbxImp5pOdYVKcVW89D4XBMyGegR40trV2VwiuX1blKCfdjMsJhiaL9pymp
|
||||
// ug1wzyQFAgMBAAECggEAK6c+PZkPPXuVCgpEcliiW6NM0r2m5K3AGKgypQ34csu3
|
||||
// z/8foCvIIFPrhCtEw5eTDQ1CHWlNOjY8vHJYJ0U6Onpx86nHIRrMBkMm8FJ1G5LJ
|
||||
// U8oKYXwqaozWu/cuPwA//OFc6I5krOzh5n8WaRMkbrgbor8AtebRX74By0AXGrXe
|
||||
// cswJI7zR96oFn4Dm7Pgvpg5Zhk1vFJ+w6QtH+4DDJ6PBvlZsRkGxYBLGVd/3qhAI
|
||||
// sBAyjFlSzuP4eCRhHOhHC/e4gmAH9evFVXB88jFyRZm3K+jQ5W5CwrVRBCV2lph6
|
||||
// 2B6P7CBJN+IjGKMhy+75y13UvvKPv9IwH8Fzl2x1gQKBgQD8qQOr7a6KhSj16wQE
|
||||
// jim2xqt9gQ2jH5No405NrKs/PFQQZnzD4YseQsiK//NUjOJiUhaT+L5jhIpzINHt
|
||||
// RJpt3bGkEZmLyjdjgTpB3GwZdXa28DNK9VdXZ19qIl/ZH0qAjKmJCRahUDASMnVi
|
||||
// M4Pkk9yx9ZIKkri4TcuMWqc0DQKBgQDlHKBTITZq/arYPD6Nl3NsoOdqVRqJrGay
|
||||
// 0TjXAVbBXe46+z5lnMsqwXb79nx14hdmSEsZULrw/3f+MnQbdjMTYLFP24visZg9
|
||||
// MN8vAiALiiiR1a+Crz+DTA1Q8sGOMVCMqMDmD7QBys3ZuWxuapm0txAiIYUtsjJZ
|
||||
// XN76T4nZ2QKBgQCHaT3igzwsWTmesxowJtEMeGWomeXpKx8h89EfqA8PkRGsyIDN
|
||||
// qq+YxEoe1RZgljEuaLhZDdNcGsjo8woPk9kAUPTH7fbRCMuutK+4ZJ469s1tNkcH
|
||||
// QX5SBcEJbOrZvv967ehe3VQXmJZq6kgnHVzuwKBjcC2ZJRGDFY6l5l/+cQKBgCqh
|
||||
// +Adf/8NK7paMJ0urqfPFwSodKfICXZ3apswDWMRkmSbqh4La+Uc8dsqN5Dz/VEFZ
|
||||
// JHhSeGbN8uMfOlG93eU2MehdPxtw1pZUWMNjjtj23XO9ooob2CKzbSrp8TBnZsi1
|
||||
// widNNr66oTFpeo7VUUK6acsgF6sYJJxSVr+XO1yJAoGAEhvitq8shNKcEY0xCipS
|
||||
// k1kbgyS7KKB7opVxI5+ChEqyUDijS3Y9FZixrRIWE6i2uGu86UG+v2lbKvSbM4Qm
|
||||
// xvbOcX9OVMnlRb7n8woOP10UMY+ZE2x+YEUXQTLtPYq7F66e1OfxltstMxLQA+3d
|
||||
// Y1d5piFV8PXK3Fg2F+Cj5qg=
|
||||
// -----END PRIVATE KEY-----
|
||||
// '
|
||||
// , $this->userId
|
||||
// );
|
||||
//
|
||||
// \OC_User::setUserId( $this->userId );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public function testpreFile_get_contents() {
|
||||
//
|
||||
// // This won't work for now because mocking of the static keymanager class isn't working :(
|
||||
//
|
||||
// // $mock = m::mock( 'alias:OCA\Encryption\Keymanager' );
|
||||
// //
|
||||
// // $mock->shouldReceive( 'getFileKey' )->times(2)->andReturn( $this->encDataShort );
|
||||
// //
|
||||
// // $encrypted = $this->proxy->postFile_get_contents( 'data/'.$this->tmpFileName, $this->encDataShortKey );
|
||||
// //
|
||||
// // $this->assertNotEquals( $this->dataShort, $encrypted );
|
||||
//
|
||||
// $decrypted = $this->proxy->postFile_get_contents( 'data/admin/files/enc-test.txt', $this->data1 );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
// class Test_CryptProxy extends UnitTestCase {
|
||||
// private $oldConfig;
|
||||
// private $oldKey;
|
||||
//
|
||||
// public function setUp(){
|
||||
// $user=OC_User::getUser();
|
||||
//
|
||||
// $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption','true');
|
||||
// OCP\Config::setAppValue('files_encryption','enable_encryption','true');
|
||||
// $this->oldKey=isset($_SESSION['privateKey'])?$_SESSION['privateKey']:null;
|
||||
//
|
||||
//
|
||||
// //set testing key
|
||||
// $_SESSION['privateKey']=md5(time());
|
||||
//
|
||||
// //clear all proxies and hooks so we can do clean testing
|
||||
// OC_FileProxy::clearProxies();
|
||||
// OC_Hook::clear('OC_Filesystem');
|
||||
//
|
||||
// //enable only the encryption hook
|
||||
// OC_FileProxy::register(new OC_FileProxy_Encryption());
|
||||
//
|
||||
// //set up temporary storage
|
||||
// OC_Filesystem::clearMounts();
|
||||
// OC_Filesystem::mount('OC_Filestorage_Temporary',array(),'/');
|
||||
//
|
||||
// OC_Filesystem::init('/'.$user.'/files');
|
||||
//
|
||||
// //set up the users home folder in the temp storage
|
||||
// $rootView=new OC_FilesystemView('');
|
||||
// $rootView->mkdir('/'.$user);
|
||||
// $rootView->mkdir('/'.$user.'/files');
|
||||
// }
|
||||
//
|
||||
// public function tearDown(){
|
||||
// OCP\Config::setAppValue('files_encryption','enable_encryption',$this->oldConfig);
|
||||
// if(!is_null($this->oldKey)){
|
||||
// $_SESSION['privateKey']=$this->oldKey;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public function testSimple(){
|
||||
// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
// $original=file_get_contents($file);
|
||||
//
|
||||
// OC_Filesystem::file_put_contents('/file',$original);
|
||||
//
|
||||
// OC_FileProxy::$enabled=false;
|
||||
// $stored=OC_Filesystem::file_get_contents('/file');
|
||||
// OC_FileProxy::$enabled=true;
|
||||
//
|
||||
// $fromFile=OC_Filesystem::file_get_contents('/file');
|
||||
// $this->assertNotEqual($original,$stored);
|
||||
// $this->assertEqual(strlen($original),strlen($fromFile));
|
||||
// $this->assertEqual($original,$fromFile);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public function testView(){
|
||||
// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
// $original=file_get_contents($file);
|
||||
//
|
||||
// $rootView=new OC_FilesystemView('');
|
||||
// $view=new OC_FilesystemView('/'.OC_User::getUser());
|
||||
// $userDir='/'.OC_User::getUser().'/files';
|
||||
//
|
||||
// $rootView->file_put_contents($userDir.'/file',$original);
|
||||
//
|
||||
// OC_FileProxy::$enabled=false;
|
||||
// $stored=$rootView->file_get_contents($userDir.'/file');
|
||||
// OC_FileProxy::$enabled=true;
|
||||
//
|
||||
// $this->assertNotEqual($original,$stored);
|
||||
// $fromFile=$rootView->file_get_contents($userDir.'/file');
|
||||
// $this->assertEqual($original,$fromFile);
|
||||
//
|
||||
// $fromFile=$view->file_get_contents('files/file');
|
||||
// $this->assertEqual($original,$fromFile);
|
||||
// }
|
||||
//
|
||||
// public function testBinary(){
|
||||
// $file=__DIR__.'/binary';
|
||||
// $original=file_get_contents($file);
|
||||
//
|
||||
// OC_Filesystem::file_put_contents('/file',$original);
|
||||
//
|
||||
// OC_FileProxy::$enabled=false;
|
||||
// $stored=OC_Filesystem::file_get_contents('/file');
|
||||
// OC_FileProxy::$enabled=true;
|
||||
//
|
||||
// $fromFile=OC_Filesystem::file_get_contents('/file');
|
||||
// $this->assertNotEqual($original,$stored);
|
||||
// $this->assertEqual(strlen($original),strlen($fromFile));
|
||||
// $this->assertEqual($original,$fromFile);
|
||||
//
|
||||
// $file=__DIR__.'/zeros';
|
||||
// $original=file_get_contents($file);
|
||||
//
|
||||
// OC_Filesystem::file_put_contents('/file',$original);
|
||||
//
|
||||
// OC_FileProxy::$enabled=false;
|
||||
// $stored=OC_Filesystem::file_get_contents('/file');
|
||||
// OC_FileProxy::$enabled=true;
|
||||
//
|
||||
// $fromFile=OC_Filesystem::file_get_contents('/file');
|
||||
// $this->assertNotEqual($original,$stored);
|
||||
// $this->assertEqual(strlen($original),strlen($fromFile));
|
||||
// }
|
||||
// }
|
226
apps/files_encryption/test/stream.php
Normal file
226
apps/files_encryption/test/stream.php
Normal file
|
@ -0,0 +1,226 @@
|
|||
// <?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 OCA\Encryption;
|
||||
//
|
||||
// class Test_Stream extends \PHPUnit_Framework_TestCase {
|
||||
//
|
||||
// function setUp() {
|
||||
//
|
||||
// \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' );
|
||||
//
|
||||
// $this->empty = '';
|
||||
//
|
||||
// $this->stream = new Stream();
|
||||
//
|
||||
// $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
||||
// $this->dataShort = 'hats';
|
||||
//
|
||||
// $this->emptyTmpFilePath = \OCP\Files::tmpFile();
|
||||
//
|
||||
// $this->dataTmpFilePath = \OCP\Files::tmpFile();
|
||||
//
|
||||
// file_put_contents( $this->dataTmpFilePath, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est." );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function testStreamOpen() {
|
||||
//
|
||||
// $stream1 = new Stream();
|
||||
//
|
||||
// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'wb', array(), $this->empty );
|
||||
//
|
||||
// // Test that resource was returned successfully
|
||||
// $this->assertTrue( $handle1 );
|
||||
//
|
||||
// // Test that file has correct size
|
||||
// $this->assertEquals( 0, $stream1->size );
|
||||
//
|
||||
// // Test that path is correct
|
||||
// $this->assertEquals( $this->emptyTmpFilePath, $stream1->rawPath );
|
||||
//
|
||||
// $stream2 = new Stream();
|
||||
//
|
||||
// $handle2 = $stream2->stream_open( 'crypt://' . $this->emptyTmpFilePath, 'wb', array(), $this->empty );
|
||||
//
|
||||
// // Test that protocol identifier is removed from path
|
||||
// $this->assertEquals( $this->emptyTmpFilePath, $stream2->rawPath );
|
||||
//
|
||||
// // "Stat failed error" prevents this test from executing
|
||||
// // $stream3 = new Stream();
|
||||
// //
|
||||
// // $handle3 = $stream3->stream_open( $this->dataTmpFilePath, 'r', array(), $this->empty );
|
||||
// //
|
||||
// // $this->assertEquals( 0, $stream3->size );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function testStreamWrite() {
|
||||
//
|
||||
// $stream1 = new Stream();
|
||||
//
|
||||
// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'r+b', array(), $this->empty );
|
||||
//
|
||||
// # what about the keymanager? there is no key for the newly created temporary file!
|
||||
//
|
||||
// $stream1->stream_write( $this->dataShort );
|
||||
//
|
||||
// }
|
||||
//
|
||||
// // function getStream( $id, $mode, $size ) {
|
||||
// //
|
||||
// // if ( $id === '' ) {
|
||||
// //
|
||||
// // $id = uniqid();
|
||||
// // }
|
||||
// //
|
||||
// //
|
||||
// // if ( !isset( $this->tmpFiles[$id] ) ) {
|
||||
// //
|
||||
// // // If tempfile with given name does not already exist, create it
|
||||
// //
|
||||
// // $file = OCP\Files::tmpFile();
|
||||
// //
|
||||
// // $this->tmpFiles[$id] = $file;
|
||||
// //
|
||||
// // } else {
|
||||
// //
|
||||
// // $file = $this->tmpFiles[$id];
|
||||
// //
|
||||
// // }
|
||||
// //
|
||||
// // $stream = fopen( $file, $mode );
|
||||
// //
|
||||
// // Stream::$sourceStreams[$id] = array( 'path' => 'dummy' . $id, 'stream' => $stream, 'size' => $size );
|
||||
// //
|
||||
// // return fopen( 'crypt://streams/'.$id, $mode );
|
||||
// //
|
||||
// // }
|
||||
// //
|
||||
// // function testStream( ){
|
||||
// //
|
||||
// // $stream = $this->getStream( 'test1', 'w', strlen( 'foobar' ) );
|
||||
// //
|
||||
// // fwrite( $stream, 'foobar' );
|
||||
// //
|
||||
// // fclose( $stream );
|
||||
// //
|
||||
// //
|
||||
// // $stream = $this->getStream( 'test1', 'r', strlen( 'foobar' ) );
|
||||
// //
|
||||
// // $data = fread( $stream, 6 );
|
||||
// //
|
||||
// // fclose( $stream );
|
||||
// //
|
||||
// // $this->assertEqual( 'foobar', $data );
|
||||
// //
|
||||
// //
|
||||
// // $file = OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
// //
|
||||
// // $source = fopen( $file, 'r' );
|
||||
// //
|
||||
// // $target = $this->getStream( 'test2', 'w', 0 );
|
||||
// //
|
||||
// // OCP\Files::streamCopy( $source, $target );
|
||||
// //
|
||||
// // fclose( $target );
|
||||
// //
|
||||
// // fclose( $source );
|
||||
// //
|
||||
// //
|
||||
// // $stream = $this->getStream( 'test2', 'r', filesize( $file ) );
|
||||
// //
|
||||
// // $data = stream_get_contents( $stream );
|
||||
// //
|
||||
// // $original = file_get_contents( $file );
|
||||
// //
|
||||
// // $this->assertEqual( strlen( $original ), strlen( $data ) );
|
||||
// //
|
||||
// // $this->assertEqual( $original, $data );
|
||||
// //
|
||||
// // }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// // class Test_CryptStream extends UnitTestCase {
|
||||
// // private $tmpFiles=array();
|
||||
// //
|
||||
// // function testStream(){
|
||||
// // $stream=$this->getStream('test1','w',strlen('foobar'));
|
||||
// // fwrite($stream,'foobar');
|
||||
// // fclose($stream);
|
||||
// //
|
||||
// // $stream=$this->getStream('test1','r',strlen('foobar'));
|
||||
// // $data=fread($stream,6);
|
||||
// // fclose($stream);
|
||||
// // $this->assertEqual('foobar',$data);
|
||||
// //
|
||||
// // $file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
// // $source=fopen($file,'r');
|
||||
// // $target=$this->getStream('test2','w',0);
|
||||
// // OCP\Files::streamCopy($source,$target);
|
||||
// // fclose($target);
|
||||
// // fclose($source);
|
||||
// //
|
||||
// // $stream=$this->getStream('test2','r',filesize($file));
|
||||
// // $data=stream_get_contents($stream);
|
||||
// // $original=file_get_contents($file);
|
||||
// // $this->assertEqual(strlen($original),strlen($data));
|
||||
// // $this->assertEqual($original,$data);
|
||||
// // }
|
||||
// //
|
||||
// // /**
|
||||
// // * get a cryptstream to a temporary file
|
||||
// // * @param string $id
|
||||
// // * @param string $mode
|
||||
// // * @param int size
|
||||
// // * @return resource
|
||||
// // */
|
||||
// // function getStream($id,$mode,$size){
|
||||
// // if($id===''){
|
||||
// // $id=uniqid();
|
||||
// // }
|
||||
// // if(!isset($this->tmpFiles[$id])){
|
||||
// // $file=OCP\Files::tmpFile();
|
||||
// // $this->tmpFiles[$id]=$file;
|
||||
// // }else{
|
||||
// // $file=$this->tmpFiles[$id];
|
||||
// // }
|
||||
// // $stream=fopen($file,$mode);
|
||||
// // OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream,'size'=>$size);
|
||||
// // return fopen('crypt://streams/'.$id,$mode);
|
||||
// // }
|
||||
// //
|
||||
// // function testBinary(){
|
||||
// // $file=__DIR__.'/binary';
|
||||
// // $source=file_get_contents($file);
|
||||
// //
|
||||
// // $stream=$this->getStream('test','w',strlen($source));
|
||||
// // fwrite($stream,$source);
|
||||
// // fclose($stream);
|
||||
// //
|
||||
// // $stream=$this->getStream('test','r',strlen($source));
|
||||
// // $data=stream_get_contents($stream);
|
||||
// // fclose($stream);
|
||||
// // $this->assertEqual(strlen($data),strlen($source));
|
||||
// // $this->assertEqual($source,$data);
|
||||
// //
|
||||
// // $file=__DIR__.'/zeros';
|
||||
// // $source=file_get_contents($file);
|
||||
// //
|
||||
// // $stream=$this->getStream('test2','w',strlen($source));
|
||||
// // fwrite($stream,$source);
|
||||
// // fclose($stream);
|
||||
// //
|
||||
// // $stream=$this->getStream('test2','r',strlen($source));
|
||||
// // $data=stream_get_contents($stream);
|
||||
// // fclose($stream);
|
||||
// // $this->assertEqual(strlen($data),strlen($source));
|
||||
// // $this->assertEqual($source,$data);
|
||||
// // }
|
||||
// // }
|
210
apps/files_encryption/test/util.php
Executable file
210
apps/files_encryption/test/util.php
Executable file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
//require_once "PHPUnit/Framework/TestCase.php";
|
||||
require_once realpath( dirname(__FILE__).'/../../../lib/base.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/proxy.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/stream.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../lib/util.php' );
|
||||
require_once realpath( dirname(__FILE__).'/../appinfo/app.php' );
|
||||
|
||||
// Load mockery files
|
||||
require_once 'Mockery/Loader.php';
|
||||
require_once 'Hamcrest/Hamcrest.php';
|
||||
$loader = new \Mockery\Loader;
|
||||
$loader->register();
|
||||
|
||||
use \Mockery as m;
|
||||
use OCA\Encryption;
|
||||
|
||||
class Test_Enc_Util extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
function setUp() {
|
||||
|
||||
\OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' );
|
||||
|
||||
// set content for encrypting / decrypting in tests
|
||||
$this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' );
|
||||
$this->dataShort = 'hats';
|
||||
$this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) );
|
||||
$this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' );
|
||||
$this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' );
|
||||
|
||||
$this->userId = 'admin';
|
||||
$this->pass = 'admin';
|
||||
|
||||
$keypair = Encryption\Crypt::createKeypair();
|
||||
|
||||
$this->genPublicKey = $keypair['publicKey'];
|
||||
$this->genPrivateKey = $keypair['privateKey'];
|
||||
|
||||
$this->publicKeyDir = '/' . 'public-keys';
|
||||
$this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption';
|
||||
$this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles';
|
||||
$this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key
|
||||
$this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key
|
||||
|
||||
$this->view = new OC_FilesystemView( '/admin' );
|
||||
|
||||
$this->mockView = m::mock('OC_FilesystemView');
|
||||
$this->util = new Encryption\Util( $this->mockView, $this->userId );
|
||||
|
||||
}
|
||||
|
||||
function tearDown(){
|
||||
|
||||
m::close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test that paths set during User construction are correct
|
||||
*/
|
||||
function testKeyPaths() {
|
||||
|
||||
$mockView = m::mock('OC_FilesystemView');
|
||||
|
||||
$util = new Encryption\Util( $mockView, $this->userId );
|
||||
|
||||
$this->assertEquals( $this->publicKeyDir, $util->getPath( 'publicKeyDir' ) );
|
||||
$this->assertEquals( $this->encryptionDir, $util->getPath( 'encryptionDir' ) );
|
||||
$this->assertEquals( $this->keyfilesPath, $util->getPath( 'keyfilesPath' ) );
|
||||
$this->assertEquals( $this->publicKeyPath, $util->getPath( 'publicKeyPath' ) );
|
||||
$this->assertEquals( $this->privateKeyPath, $util->getPath( 'privateKeyPath' ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test setup of encryption directories when they don't yet exist
|
||||
*/
|
||||
function testSetupServerSideNotSetup() {
|
||||
|
||||
$mockView = m::mock('OC_FilesystemView');
|
||||
|
||||
$mockView->shouldReceive( 'file_exists' )->times(4)->andReturn( false );
|
||||
$mockView->shouldReceive( 'mkdir' )->times(3)->andReturn( true );
|
||||
$mockView->shouldReceive( 'file_put_contents' )->withAnyArgs();
|
||||
|
||||
$util = new Encryption\Util( $mockView, $this->userId );
|
||||
|
||||
$this->assertEquals( true, $util->setupServerSide( $this->pass ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test setup of encryption directories when they already exist
|
||||
*/
|
||||
function testSetupServerSideIsSetup() {
|
||||
|
||||
$mockView = m::mock('OC_FilesystemView');
|
||||
|
||||
$mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( true );
|
||||
$mockView->shouldReceive( 'file_put_contents' )->withAnyArgs();
|
||||
|
||||
$util = new Encryption\Util( $mockView, $this->userId );
|
||||
|
||||
$this->assertEquals( true, $util->setupServerSide( $this->pass ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test checking whether account is ready for encryption, when it isn't ready
|
||||
*/
|
||||
function testReadyNotReady() {
|
||||
|
||||
$mockView = m::mock('OC_FilesystemView');
|
||||
|
||||
$mockView->shouldReceive( 'file_exists' )->times(1)->andReturn( false );
|
||||
|
||||
$util = new Encryption\Util( $mockView, $this->userId );
|
||||
|
||||
$this->assertEquals( false, $util->ready() );
|
||||
|
||||
# TODO: Add more tests here to check that if any of the dirs are
|
||||
# then false will be returned. Use strict ordering?
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test checking whether account is ready for encryption, when it is ready
|
||||
*/
|
||||
function testReadyIsReady() {
|
||||
|
||||
$mockView = m::mock('OC_FilesystemView');
|
||||
|
||||
$mockView->shouldReceive( 'file_exists' )->times(3)->andReturn( true );
|
||||
|
||||
$util = new Encryption\Util( $mockView, $this->userId );
|
||||
|
||||
$this->assertEquals( true, $util->ready() );
|
||||
|
||||
# TODO: Add more tests here to check that if any of the dirs are
|
||||
# then false will be returned. Use strict ordering?
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @brief test decryption using legacy blowfish method
|
||||
// * @depends testLegacyEncryptLong
|
||||
// */
|
||||
// function testLegacyKeyRecryptKeyfileDecrypt( $recrypted ) {
|
||||
//
|
||||
// $decrypted = Encryption\Crypt::keyDecryptKeyfile( $recrypted['data'], $recrypted['key'], $this->genPrivateKey );
|
||||
//
|
||||
// $this->assertEquals( $this->dataLong, $decrypted );
|
||||
//
|
||||
// }
|
||||
|
||||
// // Cannot use this test for now due to hidden dependencies in OC_FileCache
|
||||
// function testIsLegacyEncryptedContent() {
|
||||
//
|
||||
// $keyfileContent = OCA\Encryption\Crypt::symmetricEncryptFileContent( $this->legacyEncryptedData, 'hat' );
|
||||
//
|
||||
// $this->assertFalse( OCA\Encryption\Crypt::isLegacyEncryptedContent( $keyfileContent, '/files/admin/test.txt' ) );
|
||||
//
|
||||
// OC_FileCache::put( '/admin/files/legacy-encrypted-test.txt', $this->legacyEncryptedData );
|
||||
//
|
||||
// $this->assertTrue( OCA\Encryption\Crypt::isLegacyEncryptedContent( $this->legacyEncryptedData, '/files/admin/test.txt' ) );
|
||||
//
|
||||
// }
|
||||
|
||||
// // Cannot use this test for now due to need for different root in OC_Filesystem_view class
|
||||
// function testGetLegacyKey() {
|
||||
//
|
||||
// $c = new \OCA\Encryption\Util( $view, false );
|
||||
//
|
||||
// $bool = $c->getLegacyKey( 'admin' );
|
||||
//
|
||||
// $this->assertTrue( $bool );
|
||||
//
|
||||
// $this->assertTrue( $c->legacyKey );
|
||||
//
|
||||
// $this->assertTrue( is_int( $c->legacyKey ) );
|
||||
//
|
||||
// $this->assertTrue( strlen( $c->legacyKey ) == 20 );
|
||||
//
|
||||
// }
|
||||
|
||||
// // Cannot use this test for now due to need for different root in OC_Filesystem_view class
|
||||
// function testLegacyDecrypt() {
|
||||
//
|
||||
// $c = new OCA\Encryption\Util( $this->view, false );
|
||||
//
|
||||
// $bool = $c->getLegacyKey( 'admin' );
|
||||
//
|
||||
// $encrypted = $c->legacyEncrypt( $this->data, $c->legacyKey );
|
||||
//
|
||||
// $decrypted = $c->legacyDecrypt( $encrypted, $c->legacyKey );
|
||||
//
|
||||
// $this->assertEqual( $decrypted, $this->data );
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class Test_Encryption extends UnitTestCase {
|
||||
function testEncryption() {
|
||||
$key=uniqid();
|
||||
$file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
$source=file_get_contents($file); //nice large text file
|
||||
$encrypted=OC_Crypt::encrypt($source, $key);
|
||||
$decrypted=OC_Crypt::decrypt($encrypted, $key);
|
||||
$decrypted=rtrim($decrypted, "\0");
|
||||
$this->assertNotEqual($encrypted, $source);
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
$chunk=substr($source, 0, 8192);
|
||||
$encrypted=OC_Crypt::encrypt($chunk, $key);
|
||||
$this->assertEqual(strlen($chunk), strlen($encrypted));
|
||||
$decrypted=OC_Crypt::decrypt($encrypted, $key);
|
||||
$decrypted=rtrim($decrypted, "\0");
|
||||
$this->assertEqual($decrypted, $chunk);
|
||||
|
||||
$encrypted=OC_Crypt::blockEncrypt($source, $key);
|
||||
$decrypted=OC_Crypt::blockDecrypt($encrypted, $key);
|
||||
$this->assertNotEqual($encrypted, $source);
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
$tmpFileEncrypted=OCP\Files::tmpFile();
|
||||
OC_Crypt::encryptfile($file, $tmpFileEncrypted, $key);
|
||||
$encrypted=file_get_contents($tmpFileEncrypted);
|
||||
$decrypted=OC_Crypt::blockDecrypt($encrypted, $key);
|
||||
$this->assertNotEqual($encrypted, $source);
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
$tmpFileDecrypted=OCP\Files::tmpFile();
|
||||
OC_Crypt::decryptfile($tmpFileEncrypted, $tmpFileDecrypted, $key);
|
||||
$decrypted=file_get_contents($tmpFileDecrypted);
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
$file=OC::$SERVERROOT.'/core/img/weather-clear.png';
|
||||
$source=file_get_contents($file); //binary file
|
||||
$encrypted=OC_Crypt::encrypt($source, $key);
|
||||
$decrypted=OC_Crypt::decrypt($encrypted, $key);
|
||||
$decrypted=rtrim($decrypted, "\0");
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
$encrypted=OC_Crypt::blockEncrypt($source, $key);
|
||||
$decrypted=OC_Crypt::blockDecrypt($encrypted, $key);
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
}
|
||||
|
||||
function testBinary() {
|
||||
$key=uniqid();
|
||||
|
||||
$file=__DIR__.'/binary';
|
||||
$source=file_get_contents($file); //binary file
|
||||
$encrypted=OC_Crypt::encrypt($source, $key);
|
||||
$decrypted=OC_Crypt::decrypt($encrypted, $key);
|
||||
|
||||
$decrypted=rtrim($decrypted, "\0");
|
||||
$this->assertEqual($decrypted, $source);
|
||||
|
||||
$encrypted=OC_Crypt::blockEncrypt($source, $key);
|
||||
$decrypted=OC_Crypt::blockDecrypt($encrypted, $key, strlen($source));
|
||||
$this->assertEqual($decrypted, $source);
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class Test_CryptProxy extends UnitTestCase {
|
||||
private $oldConfig;
|
||||
private $oldKey;
|
||||
|
||||
public function setUp() {
|
||||
$user=OC_User::getUser();
|
||||
|
||||
$this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption', 'true');
|
||||
OCP\Config::setAppValue('files_encryption', 'enable_encryption', 'true');
|
||||
$this->oldKey=isset($_SESSION['enckey'])?$_SESSION['enckey']:null;
|
||||
|
||||
|
||||
//set testing key
|
||||
$_SESSION['enckey']=md5(time());
|
||||
|
||||
//clear all proxies and hooks so we can do clean testing
|
||||
OC_FileProxy::clearProxies();
|
||||
OC_Hook::clear('OC_Filesystem');
|
||||
|
||||
//enable only the encryption hook
|
||||
OC_FileProxy::register(new OC_FileProxy_Encryption());
|
||||
|
||||
//set up temporary storage
|
||||
OC_Filesystem::clearMounts();
|
||||
OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/');
|
||||
|
||||
OC_Filesystem::init('/'.$user.'/files');
|
||||
|
||||
//set up the users home folder in the temp storage
|
||||
$rootView=new OC_FilesystemView('');
|
||||
$rootView->mkdir('/'.$user);
|
||||
$rootView->mkdir('/'.$user.'/files');
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
OCP\Config::setAppValue('files_encryption', 'enable_encryption', $this->oldConfig);
|
||||
if ( ! is_null($this->oldKey)) {
|
||||
$_SESSION['enckey']=$this->oldKey;
|
||||
}
|
||||
}
|
||||
|
||||
public function testSimple() {
|
||||
$file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
$original=file_get_contents($file);
|
||||
|
||||
OC_Filesystem::file_put_contents('/file', $original);
|
||||
|
||||
OC_FileProxy::$enabled=false;
|
||||
$stored=OC_Filesystem::file_get_contents('/file');
|
||||
OC_FileProxy::$enabled=true;
|
||||
|
||||
$fromFile=OC_Filesystem::file_get_contents('/file');
|
||||
$this->assertNotEqual($original, $stored);
|
||||
$this->assertEqual(strlen($original), strlen($fromFile));
|
||||
$this->assertEqual($original, $fromFile);
|
||||
|
||||
}
|
||||
|
||||
public function testView() {
|
||||
$file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
$original=file_get_contents($file);
|
||||
|
||||
$rootView=new OC_FilesystemView('');
|
||||
$view=new OC_FilesystemView('/'.OC_User::getUser());
|
||||
$userDir='/'.OC_User::getUser().'/files';
|
||||
|
||||
$rootView->file_put_contents($userDir.'/file', $original);
|
||||
|
||||
OC_FileProxy::$enabled=false;
|
||||
$stored=$rootView->file_get_contents($userDir.'/file');
|
||||
OC_FileProxy::$enabled=true;
|
||||
|
||||
$this->assertNotEqual($original, $stored);
|
||||
$fromFile=$rootView->file_get_contents($userDir.'/file');
|
||||
$this->assertEqual($original, $fromFile);
|
||||
|
||||
$fromFile=$view->file_get_contents('files/file');
|
||||
$this->assertEqual($original, $fromFile);
|
||||
}
|
||||
|
||||
public function testBinary() {
|
||||
$file=__DIR__.'/binary';
|
||||
$original=file_get_contents($file);
|
||||
|
||||
OC_Filesystem::file_put_contents('/file', $original);
|
||||
|
||||
OC_FileProxy::$enabled=false;
|
||||
$stored=OC_Filesystem::file_get_contents('/file');
|
||||
OC_FileProxy::$enabled=true;
|
||||
|
||||
$fromFile=OC_Filesystem::file_get_contents('/file');
|
||||
$this->assertNotEqual($original, $stored);
|
||||
$this->assertEqual(strlen($original), strlen($fromFile));
|
||||
$this->assertEqual($original, $fromFile);
|
||||
|
||||
$file=__DIR__.'/zeros';
|
||||
$original=file_get_contents($file);
|
||||
|
||||
OC_Filesystem::file_put_contents('/file', $original);
|
||||
|
||||
OC_FileProxy::$enabled=false;
|
||||
$stored=OC_Filesystem::file_get_contents('/file');
|
||||
OC_FileProxy::$enabled=true;
|
||||
|
||||
$fromFile=OC_Filesystem::file_get_contents('/file');
|
||||
$this->assertNotEqual($original, $stored);
|
||||
$this->assertEqual(strlen($original), strlen($fromFile));
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
class Test_CryptStream extends UnitTestCase {
|
||||
private $tmpFiles=array();
|
||||
|
||||
function testStream() {
|
||||
$stream=$this->getStream('test1', 'w', strlen('foobar'));
|
||||
fwrite($stream, 'foobar');
|
||||
fclose($stream);
|
||||
|
||||
$stream=$this->getStream('test1', 'r', strlen('foobar'));
|
||||
$data=fread($stream, 6);
|
||||
fclose($stream);
|
||||
$this->assertEqual('foobar', $data);
|
||||
|
||||
$file=OC::$SERVERROOT.'/3rdparty/MDB2.php';
|
||||
$source=fopen($file, 'r');
|
||||
$target=$this->getStream('test2', 'w', 0);
|
||||
OCP\Files::streamCopy($source, $target);
|
||||
fclose($target);
|
||||
fclose($source);
|
||||
|
||||
$stream=$this->getStream('test2', 'r', filesize($file));
|
||||
$data=stream_get_contents($stream);
|
||||
$original=file_get_contents($file);
|
||||
$this->assertEqual(strlen($original), strlen($data));
|
||||
$this->assertEqual($original, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a cryptstream to a temporary file
|
||||
* @param string $id
|
||||
* @param string $mode
|
||||
* @param int size
|
||||
* @return resource
|
||||
*/
|
||||
function getStream($id, $mode, $size) {
|
||||
if ($id==='') {
|
||||
$id=uniqid();
|
||||
}
|
||||
if ( ! isset($this->tmpFiles[$id])) {
|
||||
$file=OCP\Files::tmpFile();
|
||||
$this->tmpFiles[$id]=$file;
|
||||
} else {
|
||||
$file=$this->tmpFiles[$id];
|
||||
}
|
||||
$stream=fopen($file, $mode);
|
||||
OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id, 'stream'=>$stream, 'size'=>$size);
|
||||
return fopen('crypt://streams/'.$id, $mode);
|
||||
}
|
||||
|
||||
function testBinary() {
|
||||
$file=__DIR__.'/binary';
|
||||
$source=file_get_contents($file);
|
||||
|
||||
$stream=$this->getStream('test', 'w', strlen($source));
|
||||
fwrite($stream, $source);
|
||||
fclose($stream);
|
||||
|
||||
$stream=$this->getStream('test', 'r', strlen($source));
|
||||
$data=stream_get_contents($stream);
|
||||
fclose($stream);
|
||||
$this->assertEqual(strlen($data), strlen($source));
|
||||
$this->assertEqual($source, $data);
|
||||
|
||||
$file=__DIR__.'/zeros';
|
||||
$source=file_get_contents($file);
|
||||
|
||||
$stream=$this->getStream('test2', 'w', strlen($source));
|
||||
fwrite($stream, $source);
|
||||
fclose($stream);
|
||||
|
||||
$stream=$this->getStream('test2', 'r', strlen($source));
|
||||
$data=stream_get_contents($stream);
|
||||
fclose($stream);
|
||||
$this->assertEqual(strlen($data), strlen($source));
|
||||
$this->assertEqual($source, $data);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
"Fill out all required fields" => "กรอกข้อมูลในช่องข้อมูลที่จำเป็นต้องกรอกทั้งหมด",
|
||||
"Please provide a valid Dropbox app key and secret." => "กรุณากรอกรหัส app key ของ Dropbox และรหัสลับ",
|
||||
"Error configuring Google Drive storage" => "เกิดข้อผิดพลาดในการกำหนดค่าการจัดเก็บข้อมูลในพื้นที่ของ Google Drive",
|
||||
"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>คำเตือน:</b> \"smbclient\" ยังไม่ได้ถูกติดตั้ง. การชี้ CIFS/SMB เพื่อแชร์ข้อมูลไม่สามารถกระทำได้ กรุณาสอบถามข้อมูลเพิ่มเติมจากผู้ดูแลระบบเพื่อติดตั้ง.",
|
||||
"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>คำเตือน:</b> การสนับสนุนการใช้งาน FTP ในภาษา PHP ยังไม่ได้ถูกเปิดใช้งานหรือถูกติดตั้ง. การชี้ FTP เพื่อแชร์ข้อมูลไม่สามารถดำเนินการได้ กรุณาสอบถามข้อมูลเพิ่มเติมจากผู้ดูแลระบบเพื่อติดตั้ง",
|
||||
"External Storage" => "พื้นทีจัดเก็บข้อมูลจากภายนอก",
|
||||
"Mount point" => "จุดชี้ตำแหน่ง",
|
||||
"Backend" => "ด้านหลังระบบ",
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"<b>Warning:</b> Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "<b>Varning:</b> Apps user_ldap och user_webdavauth är inkompatibla. Oväntade problem kan uppstå. Be din systemadministratör att inaktivera en av dom.",
|
||||
"<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "<b>Varning:</b> PHP LDAP - modulen är inte installerad, serversidan kommer inte att fungera. Kontakta din systemadministratör för installation.",
|
||||
"Host" => "Server",
|
||||
"You can omit the protocol, except you require SSL. Then start with ldaps://" => "Du behöver inte ange protokoll förutom om du använder SSL. Starta då med ldaps://",
|
||||
"Base DN" => "Start DN",
|
||||
"One Base DN per line" => "Ett Start DN per rad",
|
||||
"You can specify Base DN for users and groups in the Advanced tab" => "Du kan ange start DN för användare och grupper under fliken Avancerat",
|
||||
"User DN" => "Användare DN",
|
||||
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN för användaren som skall användas, t.ex. uid=agent, dc=example, dc=com. För anonym åtkomst, lämna DN och lösenord tomt.",
|
||||
|
@ -19,7 +21,9 @@
|
|||
"without any placeholder, e.g. \"objectClass=posixGroup\"." => "utan platshållare, t.ex. \"objectClass=posixGroup\".",
|
||||
"Port" => "Port",
|
||||
"Base User Tree" => "Bas för användare i katalogtjänst",
|
||||
"One User Base DN per line" => "En Användare start DN per rad",
|
||||
"Base Group Tree" => "Bas för grupper i katalogtjänst",
|
||||
"One Group Base DN per line" => "En Grupp start DN per rad",
|
||||
"Group-Member association" => "Attribut för gruppmedlemmar",
|
||||
"Use TLS" => "Använd TLS",
|
||||
"Do not use it for SSL connections, it will fail." => "Använd inte för SSL-anslutningar, det kommer inte att fungera.",
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"<b>Warning:</b> Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "<b>คำเตือน:</b> แอปฯ user_ldap และ user_webdavauth ไม่สามารถใช้งานร่วมกันได้. คุณอาจประสพปัญหาที่ไม่คาดคิดจากเหตุการณ์ดังกล่าว กรุณาติดต่อผู้ดูแลระบบของคุณเพื่อระงับการใช้งานแอปฯ ตัวใดตัวหนึ่งข้างต้น",
|
||||
"<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "<b>คำเตือน:</b> โมดูล PHP LDAP ยังไม่ได้ถูกติดตั้ง, ระบบด้านหลังจะไม่สามารถทำงานได้ กรุณาติดต่อผู้ดูแลระบบของคุณเพื่อทำการติดตั้งโมดูลดังกล่าว",
|
||||
"Host" => "โฮสต์",
|
||||
"You can omit the protocol, except you require SSL. Then start with ldaps://" => "คุณสามารถปล่อยช่องโปรโตคอลเว้นไว้ได้, ยกเว้นกรณีที่คุณต้องการใช้ SSL จากนั้นเริ่มต้นด้วย ldaps://",
|
||||
"Base DN" => "DN ฐาน",
|
||||
"One Base DN per line" => "หนึ่ง Base DN ต่อบรรทัด",
|
||||
"You can specify Base DN for users and groups in the Advanced tab" => "คุณสามารถระบุ DN หลักสำหรับผู้ใช้งานและกลุ่มต่างๆในแท็บขั้นสูงได้",
|
||||
"User DN" => "DN ของผู้ใช้งาน",
|
||||
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN ของผู้ใช้งานที่เป็นลูกค้าอะไรก็ตามที่ผูกอยู่ด้วย เช่น uid=agent, dc=example, dc=com, สำหรับการเข้าถึงโดยบุคคลนิรนาม, ให้เว้นว่าง DN และ รหัสผ่านเอาไว้",
|
||||
|
@ -18,7 +21,9 @@
|
|||
"without any placeholder, e.g. \"objectClass=posixGroup\"." => "โดยไม่ต้องมีตัวยึดใดๆ, เช่น \"objectClass=posixGroup\",",
|
||||
"Port" => "พอร์ต",
|
||||
"Base User Tree" => "รายการผู้ใช้งานหลักแบบ Tree",
|
||||
"One User Base DN per line" => "หนึ่ง User Base DN ต่อบรรทัด",
|
||||
"Base Group Tree" => "รายการกลุ่มหลักแบบ Tree",
|
||||
"One Group Base DN per line" => "หนึ่ง Group Base DN ต่อบรรทัด",
|
||||
"Group-Member association" => "ความสัมพันธ์ของสมาชิกในกลุ่ม",
|
||||
"Use TLS" => "ใช้ TLS",
|
||||
"Do not use it for SSL connections, it will fail." => "กรุณาอย่าใช้การเชื่อมต่อแบบ SSL การเชื่อมต่อจะเกิดการล้มเหลว",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"URL: http://" => "URL: http://"
|
||||
"WebDAV Authentication" => "WebDAV Autentisering",
|
||||
"URL: http://" => "URL: http://",
|
||||
"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud kommer skicka användaruppgifterna till denna URL. Denna plugin kontrollerar svaret och tolkar HTTP-statuskoderna 401 och 403 som felaktiga uppgifter, och alla andra svar som giltiga uppgifter."
|
||||
);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"WebDAV URL: http://" => "WebDAV URL: http://"
|
||||
"WebDAV Authentication" => "WebDAV Authentication",
|
||||
"URL: http://" => "URL: http://",
|
||||
"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud จะส่งข้อมูลการเข้าใช้งานของผู้ใช้งานไปยังที่อยู่ URL ดังกล่าวนี้ ปลั๊กอินดังกล่าวจะทำการตรวจสอบข้อมูลที่โต้ตอบกลับมาและจะทำการแปลรหัส HTTP statuscodes 401 และ 403 ให้เป็นข้อมูลการเข้าใช้งานที่ไม่สามารถใช้งานได้ ส่วนข้อมูลอื่นๆที่เหลือทั้งหมดจะเป็นข้อมูลการเข้าใช้งานที่สามารถใช้งานได้"
|
||||
);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"URL: http://" => "URL:http://"
|
||||
"WebDAV Authentication" => "WebDAV 认证",
|
||||
"URL: http://" => "URL:http://",
|
||||
"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud 将会发送用户的身份到此 URL。这个插件检查返回值并且将 HTTP 状态编码 401 和 403 解释为非法身份,其他所有返回值为合法身份。"
|
||||
);
|
||||
|
|
|
@ -88,7 +88,7 @@ var OC={
|
|||
PERMISSION_DELETE:8,
|
||||
PERMISSION_SHARE:16,
|
||||
webroot:oc_webroot,
|
||||
appswebroots:oc_appswebroots,
|
||||
appswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false,
|
||||
currentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false,
|
||||
coreApps:['', 'admin','log','search','settings','core','3rdparty'],
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"Ok" => "قبول",
|
||||
"Error" => "خطا",
|
||||
"Password" => "گذرواژه",
|
||||
"Unshare" => "لغو اشتراک",
|
||||
"create" => "ایجاد",
|
||||
"ownCloud password reset" => "پسورد ابرهای شما تغییرکرد",
|
||||
"Use the following link to reset your password: {link}" => "از لینک زیر جهت دوباره سازی پسورد استفاده کنید :\n{link}",
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"User %s shared a file with you" => "ผู้ใช้งาน %s ได้แชร์ไฟล์ให้กับคุณ",
|
||||
"User %s shared a folder with you" => "ผู้ใช้งาน %s ได้แชร์โฟลเดอร์ให้กับคุณ",
|
||||
"User %s shared the file \"%s\" with you. It is available for download here: %s" => "ผู้ใช้งาน %s ได้แชร์ไฟล์ \"%s\" ให้กับคุณ และคุณสามารถสามารถดาวน์โหลดไฟล์ดังกล่าวได้จากที่นี่: %s",
|
||||
"User %s shared the folder \"%s\" with you. It is available for download here: %s" => "ผู้ใช้งาน %s ได้แชร์โฟลเดอร์ \"%s\" ให้กับคุณ และคุณสามารถดาวน์โหลดโฟลเดอร์ดังกล่าวได้จากที่นี่: %s",
|
||||
"Category type not provided." => "ยังไม่ได้ระบุชนิดของหมวดหมู่",
|
||||
"No category to add?" => "ไม่มีหมวดหมู่ที่ต้องการเพิ่ม?",
|
||||
"This category already exists: " => "หมวดหมู่นี้มีอยู่แล้ว: ",
|
||||
|
@ -39,6 +43,8 @@
|
|||
"Share with link" => "แชร์ด้วยลิงก์",
|
||||
"Password protect" => "ใส่รหัสผ่านไว้",
|
||||
"Password" => "รหัสผ่าน",
|
||||
"Email link to person" => "ส่งลิงก์ให้ทางอีเมล",
|
||||
"Send" => "ส่ง",
|
||||
"Set expiration date" => "กำหนดวันที่หมดอายุ",
|
||||
"Expiration date" => "วันที่หมดอายุ",
|
||||
"Share via email:" => "แชร์ผ่านทางอีเมล",
|
||||
|
@ -55,6 +61,8 @@
|
|||
"Password protected" => "ใส่รหัสผ่านไว้",
|
||||
"Error unsetting expiration date" => "เกิดข้อผิดพลาดในการยกเลิกการตั้งค่าวันที่หมดอายุ",
|
||||
"Error setting expiration date" => "เกิดข้อผิดพลาดในการตั้งค่าวันที่หมดอายุ",
|
||||
"Sending ..." => "กำลังส่ง...",
|
||||
"Email sent" => "ส่งอีเมล์แล้ว",
|
||||
"ownCloud password reset" => "รีเซ็ตรหัสผ่าน ownCloud",
|
||||
"Use the following link to reset your password: {link}" => "ใช้ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่านของคุณใหม่: {link}",
|
||||
"You will receive a link to reset your password via Email." => "คุณจะได้รับลิงค์เพื่อกำหนดรหัสผ่านใหม่ทางอีเมล์",
|
||||
|
@ -118,5 +126,6 @@
|
|||
"remember" => "จำรหัสผ่าน",
|
||||
"Log in" => "เข้าสู่ระบบ",
|
||||
"prev" => "ก่อนหน้า",
|
||||
"next" => "ถัดไป"
|
||||
"next" => "ถัดไป",
|
||||
"Updating ownCloud to version %s, this may take a while." => "กำลังอัพเดท ownCloud ไปเป็นรุ่น %s, กรุณารอสักครู่"
|
||||
);
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
<?php $TRANSLATIONS = array(
|
||||
"User %s shared a file with you" => "%s kullanıcısı sizinle bir dosyayı paylaştı",
|
||||
"User %s shared a folder with you" => "%s kullanıcısı sizinle bir dizini paylaştı",
|
||||
"User %s shared the file \"%s\" with you. It is available for download here: %s" => "%s kullanıcısı \"%s\" dosyasını sizinle paylaştı. %s adresinden indirilebilir",
|
||||
"User %s shared the folder \"%s\" with you. It is available for download here: %s" => "%s kullanıcısı \"%s\" dizinini sizinle paylaştı. %s adresinden indirilebilir",
|
||||
"Category type not provided." => "Kategori türü desteklenmemektedir.",
|
||||
"No category to add?" => "Eklenecek kategori yok?",
|
||||
"This category already exists: " => "Bu kategori zaten mevcut: ",
|
||||
"Object type not provided." => "Nesne türü desteklenmemektedir.",
|
||||
"%s ID not provided." => "%s ID belirtilmedi.",
|
||||
"Error adding %s to favorites." => "%s favorilere eklenirken hata oluştu",
|
||||
"No categories selected for deletion." => "Silmek için bir kategori seçilmedi",
|
||||
"Error removing %s from favorites." => "%s favorilere çıkarılırken hata oluştu",
|
||||
"Settings" => "Ayarlar",
|
||||
"seconds ago" => "saniye önce",
|
||||
"1 minute ago" => "1 dakika önce",
|
||||
|
@ -25,18 +32,25 @@
|
|||
"Ok" => "Tamam",
|
||||
"The object type is not specified." => "Nesne türü belirtilmemiş.",
|
||||
"Error" => "Hata",
|
||||
"The app name is not specified." => "uygulama adı belirtilmedi.",
|
||||
"The required file {file} is not installed!" => "İhtiyaç duyulan {file} dosyası kurulu değil.",
|
||||
"Error while sharing" => "Paylaşım sırasında hata ",
|
||||
"Error while unsharing" => "Paylaşım iptal ediliyorken hata",
|
||||
"Error while changing permissions" => "İzinleri değiştirirken hata oluştu",
|
||||
"Shared with you and the group {group} by {owner}" => " {owner} tarafından sizinle ve {group} ile paylaştırılmış",
|
||||
"Shared with you by {owner}" => "{owner} trafından sizinle paylaştırıldı",
|
||||
"Share with" => "ile Paylaş",
|
||||
"Share with link" => "Bağlantı ile paylaş",
|
||||
"Password protect" => "Şifre korunması",
|
||||
"Password" => "Parola",
|
||||
"Email link to person" => "Kişiye e-posta linki",
|
||||
"Send" => "Gönder",
|
||||
"Set expiration date" => "Son kullanma tarihini ayarla",
|
||||
"Expiration date" => "Son kullanım tarihi",
|
||||
"Share via email:" => "Eposta ile paylaş",
|
||||
"No people found" => "Kişi bulunamadı",
|
||||
"Resharing is not allowed" => "Tekrar paylaşmaya izin verilmiyor",
|
||||
"Shared in {item} with {user}" => " {item} içinde {user} ile paylaşılanlarlar",
|
||||
"Unshare" => "Paylaşılmayan",
|
||||
"can edit" => "düzenleyebilir",
|
||||
"access control" => "erişim kontrolü",
|
||||
|
@ -45,6 +59,8 @@
|
|||
"delete" => "sil",
|
||||
"share" => "paylaş",
|
||||
"Password protected" => "Paralo korumalı",
|
||||
"Error unsetting expiration date" => "Geçerlilik tarihi tanımlama kaldırma hatası",
|
||||
"Error setting expiration date" => "Geçerlilik tarihi tanımlama hatası",
|
||||
"Sending ..." => "Gönderiliyor...",
|
||||
"Email sent" => "Eposta gönderildi",
|
||||
"ownCloud password reset" => "ownCloud parola sıfırlama",
|
||||
|
@ -68,6 +84,9 @@
|
|||
"Edit categories" => "Kategorileri düzenle",
|
||||
"Add" => "Ekle",
|
||||
"Security Warning" => "Güvenlik Uyarisi",
|
||||
"No secure random number generator is available, please enable the PHP OpenSSL extension." => "Güvenli rasgele sayı üreticisi bulunamadı. Lütfen PHP OpenSSL eklentisini etkinleştirin.",
|
||||
"Without a secure random number generator an attacker may be able to predict password reset tokens and take over your account." => "Güvenli rasgele sayı üreticisi olmadan saldırganlar parola sıfırlama simgelerini tahmin edip hesabınızı ele geçirebilir.",
|
||||
"Your data directory and your files are probably accessible from the internet. The .htaccess file that ownCloud provides is not working. We strongly suggest that you configure your webserver in a way that the data directory is no longer accessible or you move the data directory outside the webserver document root." => "data dizininiz ve dosyalarınız büyük ihtimalle internet üzerinden erişilebilir. Owncloud tarafından sağlanan .htaccess dosyası çalışmıyor. Web sunucunuzu yapılandırarak data dizinine erişimi kapatmanızı veya data dizinini web sunucu döküman dizini dışına almanızı şiddetle tavsiye ederiz.",
|
||||
"Create an <strong>admin account</strong>" => "Bir <strong>yönetici hesabı</strong> oluşturun",
|
||||
"Advanced" => "Gelişmiş",
|
||||
"Data folder" => "Veri klasörü",
|
||||
|
@ -101,9 +120,12 @@
|
|||
"web services under your control" => "kontrolünüzdeki web servisleri",
|
||||
"Log out" => "Çıkış yap",
|
||||
"Automatic logon rejected!" => "Otomatik oturum açma reddedildi!",
|
||||
"If you did not change your password recently, your account may be compromised!" => "Yakın zamanda parolanızı değiştirmedi iseniz hesabınız riske girebilir.",
|
||||
"Please change your password to secure your account again." => "Hesabınızı korumak için lütfen parolanızı değiştirin.",
|
||||
"Lost your password?" => "Parolanızı mı unuttunuz?",
|
||||
"remember" => "hatırla",
|
||||
"Log in" => "Giriş yap",
|
||||
"prev" => "önceki",
|
||||
"next" => "sonraki"
|
||||
"next" => "sonraki",
|
||||
"Updating ownCloud to version %s, this may take a while." => "Owncloud %s versiyonuna güncelleniyor. Biraz zaman alabilir."
|
||||
);
|
||||
|
|
|
@ -7,7 +7,15 @@
|
|||
<?php foreach ($_['cssfiles'] as $cssfile): ?>
|
||||
<link rel="stylesheet" href="<?php echo $cssfile; ?>" type="text/css" media="screen" />
|
||||
<?php endforeach; ?>
|
||||
<<<<<<< HEAD
|
||||
<script type="text/javascript" src="<?php echo OC_Helper::linkToRoute('js_config');?>"></script>
|
||||
=======
|
||||
<script type="text/javascript">
|
||||
var oc_debug = <?php echo (defined('DEBUG') && DEBUG) ? 'true' : 'false'; ?>;
|
||||
var oc_webroot = '<?php echo OC::$WEBROOT; ?>';
|
||||
var oc_requesttoken = '<?php echo $_['requesttoken']; ?>';
|
||||
</script>
|
||||
>>>>>>> master
|
||||
<?php foreach ($_['jsfiles'] as $jsfile): ?>
|
||||
<script type="text/javascript" src="<?php echo $jsfile; ?>"></script>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
@ -7,7 +7,19 @@
|
|||
<?php foreach($_['cssfiles'] as $cssfile): ?>
|
||||
<link rel="stylesheet" href="<?php echo $cssfile; ?>" type="text/css" media="screen" />
|
||||
<?php endforeach; ?>
|
||||
<<<<<<< HEAD
|
||||
<script type="text/javascript" src="<?php echo OC_Helper::linkToRoute('js_config');?>"></script>
|
||||
=======
|
||||
<script type="text/javascript">
|
||||
var oc_debug = <?php echo (defined('DEBUG') && DEBUG) ? 'true' : 'false'; ?>;
|
||||
var oc_webroot = '<?php echo OC::$WEBROOT; ?>';
|
||||
var oc_requesttoken = '<?php echo $_['requesttoken']; ?>';
|
||||
var datepickerFormatDate = <?php echo json_encode($l->l('jsdate', 'jsdate')) ?>;
|
||||
var dayNames = <?php echo json_encode(array((string)$l->t('Sunday'), (string)$l->t('Monday'), (string)$l->t('Tuesday'), (string)$l->t('Wednesday'), (string)$l->t('Thursday'), (string)$l->t('Friday'), (string)$l->t('Saturday'))) ?>;
|
||||
var monthNames = <?php echo json_encode(array((string)$l->t('January'), (string)$l->t('February'), (string)$l->t('March'), (string)$l->t('April'), (string)$l->t('May'), (string)$l->t('June'), (string)$l->t('July'), (string)$l->t('August'), (string)$l->t('September'), (string)$l->t('October'), (string)$l->t('November'), (string)$l->t('December'))) ?>;
|
||||
var firstDay = <?php echo json_encode($l->l('firstday', 'firstday')) ?>;
|
||||
</script>
|
||||
>>>>>>> master
|
||||
<?php foreach($_['jsfiles'] as $jsfile): ?>
|
||||
<script type="text/javascript" src="<?php echo $jsfile; ?>"></script>
|
||||
<?php endforeach; ?>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue