diff options
76 files changed, 1683 insertions, 385 deletions
diff --git a/apps/files_external/l10n/cs_CZ.js b/apps/files_external/l10n/cs_CZ.js index e9a24ba73f8..5ac3b82d67f 100644 --- a/apps/files_external/l10n/cs_CZ.js +++ b/apps/files_external/l10n/cs_CZ.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "Neuspokojivé parametry ověřovacího mechanismu", "Insufficient data: %s" : "Nedostatečná data: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Úložiště s id \"%i\" uživatelé nemohou upravovat", "Personal" : "Osobní", "System" : "Systém", "Grant access" : "Povolit přístup", @@ -63,6 +64,7 @@ OC.L10N.register( "Login credentials" : "Přihlašovací údaje", "Username and password" : "Uživatelské jméno a heslo", "Session credentials" : "Přihlašovací údaje sezení", + "User provided" : "Poskytnuto uživatelem", "RSA public key" : "RSA veřejný klíč", "Public key" : "Veřejný klíč", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/cs_CZ.json b/apps/files_external/l10n/cs_CZ.json index aa991682b7d..a21b78f02c7 100644 --- a/apps/files_external/l10n/cs_CZ.json +++ b/apps/files_external/l10n/cs_CZ.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "Neuspokojivé parametry ověřovacího mechanismu", "Insufficient data: %s" : "Nedostatečná data: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Úložiště s id \"%i\" uživatelé nemohou upravovat", "Personal" : "Osobní", "System" : "Systém", "Grant access" : "Povolit přístup", @@ -61,6 +62,7 @@ "Login credentials" : "Přihlašovací údaje", "Username and password" : "Uživatelské jméno a heslo", "Session credentials" : "Přihlašovací údaje sezení", + "User provided" : "Poskytnuto uživatelem", "RSA public key" : "RSA veřejný klíč", "Public key" : "Veřejný klíč", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/fi_FI.js b/apps/files_external/l10n/fi_FI.js index f7ec6fea3b3..23b9227348c 100644 --- a/apps/files_external/l10n/fi_FI.js +++ b/apps/files_external/l10n/fi_FI.js @@ -45,6 +45,7 @@ OC.L10N.register( "Password" : "Salasana", "Rackspace" : "Rackspace", "API key" : "API-avain", + "Login credentials" : "Kirjautumistiedot", "Username and password" : "Käyttäjätunnus ja salasana", "Session credentials" : "Istunnon tunnistetiedot", "RSA public key" : "Julkinen RSA-avain", diff --git a/apps/files_external/l10n/fi_FI.json b/apps/files_external/l10n/fi_FI.json index 368121feae8..2c778205e10 100644 --- a/apps/files_external/l10n/fi_FI.json +++ b/apps/files_external/l10n/fi_FI.json @@ -43,6 +43,7 @@ "Password" : "Salasana", "Rackspace" : "Rackspace", "API key" : "API-avain", + "Login credentials" : "Kirjautumistiedot", "Username and password" : "Käyttäjätunnus ja salasana", "Session credentials" : "Istunnon tunnistetiedot", "RSA public key" : "Julkinen RSA-avain", diff --git a/apps/files_external/l10n/he.js b/apps/files_external/l10n/he.js index 3da4dd67776..83ff5a524d0 100644 --- a/apps/files_external/l10n/he.js +++ b/apps/files_external/l10n/he.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "פרמטרים של מכניזם אימות אינם מספקים", "Insufficient data: %s" : "מידע לא מספק: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "האחסון עם זהות \"%i\" לא ניתן לעריכה", "Personal" : "אישי", "System" : "מערכת", "Grant access" : "הענקת גישה", @@ -63,6 +64,7 @@ OC.L10N.register( "Login credentials" : "פרטי הכניסה", "Username and password" : "שם משתמש וסיסמא", "Session credentials" : "אישורי סשן", + "User provided" : "סופק על ידי משתמש", "RSA public key" : "מפתח ציבורי RSA", "Public key" : "מפתח ציבורי", "Amazon S3" : "אמזון S3", diff --git a/apps/files_external/l10n/he.json b/apps/files_external/l10n/he.json index 9666346681c..71e07d5f6af 100644 --- a/apps/files_external/l10n/he.json +++ b/apps/files_external/l10n/he.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "פרמטרים של מכניזם אימות אינם מספקים", "Insufficient data: %s" : "מידע לא מספק: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "האחסון עם זהות \"%i\" לא ניתן לעריכה", "Personal" : "אישי", "System" : "מערכת", "Grant access" : "הענקת גישה", @@ -61,6 +62,7 @@ "Login credentials" : "פרטי הכניסה", "Username and password" : "שם משתמש וסיסמא", "Session credentials" : "אישורי סשן", + "User provided" : "סופק על ידי משתמש", "RSA public key" : "מפתח ציבורי RSA", "Public key" : "מפתח ציבורי", "Amazon S3" : "אמזון S3", diff --git a/apps/files_external/l10n/it.js b/apps/files_external/l10n/it.js index 54192813b2a..c27a92d76f4 100644 --- a/apps/files_external/l10n/it.js +++ b/apps/files_external/l10n/it.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "Parametri del meccanismo di autenticazione non soddisfatti", "Insufficient data: %s" : "Dati insufficienti: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "L'archiviazione con ID \"%i\" non è modificabile dall'utente", "Personal" : "Personale", "System" : "Sistema", "Grant access" : "Concedi l'accesso", @@ -63,6 +64,7 @@ OC.L10N.register( "Login credentials" : "Credenziali di accesso", "Username and password" : "Nome utente e password", "Session credentials" : "Credenziali di sessione", + "User provided" : "Fornita dall'utente", "RSA public key" : "Chiave pubblica RSA", "Public key" : "Chiave pubblica", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/it.json b/apps/files_external/l10n/it.json index 3bc5ee133fc..cf7775f1d0e 100644 --- a/apps/files_external/l10n/it.json +++ b/apps/files_external/l10n/it.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "Parametri del meccanismo di autenticazione non soddisfatti", "Insufficient data: %s" : "Dati insufficienti: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "L'archiviazione con ID \"%i\" non è modificabile dall'utente", "Personal" : "Personale", "System" : "Sistema", "Grant access" : "Concedi l'accesso", @@ -61,6 +62,7 @@ "Login credentials" : "Credenziali di accesso", "Username and password" : "Nome utente e password", "Session credentials" : "Credenziali di sessione", + "User provided" : "Fornita dall'utente", "RSA public key" : "Chiave pubblica RSA", "Public key" : "Chiave pubblica", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/ja.js b/apps/files_external/l10n/ja.js index 1deff5971a9..fafe03c4fa0 100644 --- a/apps/files_external/l10n/ja.js +++ b/apps/files_external/l10n/ja.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "認証のためのパラメータが不十分です", "Insufficient data: %s" : "データが不足しています: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "ストレージID \"%i\" はユーザーが編集できません", "Personal" : "個人", "System" : "システム", "Grant access" : "アクセスを許可", @@ -60,6 +61,7 @@ OC.L10N.register( "Identity endpoint URL" : "認証エンドポイントURL", "Rackspace" : "Rackspace", "API key" : "APIキー", + "Login credentials" : "ログイン資格情報", "Username and password" : "ユーザー名とパスワード", "Session credentials" : "セッション資格情報", "RSA public key" : "RSA公開鍵", diff --git a/apps/files_external/l10n/ja.json b/apps/files_external/l10n/ja.json index 744a63c929b..0d1f1729dae 100644 --- a/apps/files_external/l10n/ja.json +++ b/apps/files_external/l10n/ja.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "認証のためのパラメータが不十分です", "Insufficient data: %s" : "データが不足しています: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "ストレージID \"%i\" はユーザーが編集できません", "Personal" : "個人", "System" : "システム", "Grant access" : "アクセスを許可", @@ -58,6 +59,7 @@ "Identity endpoint URL" : "認証エンドポイントURL", "Rackspace" : "Rackspace", "API key" : "APIキー", + "Login credentials" : "ログイン資格情報", "Username and password" : "ユーザー名とパスワード", "Session credentials" : "セッション資格情報", "RSA public key" : "RSA公開鍵", diff --git a/apps/files_external/l10n/nl.js b/apps/files_external/l10n/nl.js index adc2302d9c6..a6dd5164992 100644 --- a/apps/files_external/l10n/nl.js +++ b/apps/files_external/l10n/nl.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters", "Insufficient data: %s" : "Onvoldoende gegevens: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Opslag met id \"%i\" is niet te bewerken door gebruiker", "Personal" : "Persoonlijk", "System" : "Systeem", "Grant access" : "Sta toegang toe", @@ -63,6 +64,7 @@ OC.L10N.register( "Login credentials" : "Inloggegevens", "Username and password" : "Gebruikersnaam en wachtwoord", "Session credentials" : "Sessie inloggegevens", + "User provided" : "Gebruiker gaf op", "RSA public key" : "RSA publieke sleutel", "Public key" : "Publieke sleutel", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/nl.json b/apps/files_external/l10n/nl.json index da7353a4bde..03b8953a62b 100644 --- a/apps/files_external/l10n/nl.json +++ b/apps/files_external/l10n/nl.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "Onvoldoende authenticatiemechanisme parameters", "Insufficient data: %s" : "Onvoldoende gegevens: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Opslag met id \"%i\" is niet te bewerken door gebruiker", "Personal" : "Persoonlijk", "System" : "Systeem", "Grant access" : "Sta toegang toe", @@ -61,6 +62,7 @@ "Login credentials" : "Inloggegevens", "Username and password" : "Gebruikersnaam en wachtwoord", "Session credentials" : "Sessie inloggegevens", + "User provided" : "Gebruiker gaf op", "RSA public key" : "RSA publieke sleutel", "Public key" : "Publieke sleutel", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/pt_BR.js b/apps/files_external/l10n/pt_BR.js index 46b10051238..4a301a306ab 100644 --- a/apps/files_external/l10n/pt_BR.js +++ b/apps/files_external/l10n/pt_BR.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "Parâmetros de mecanismos de autenticação não satisfeitos", "Insufficient data: %s" : "Dados insuficientes: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Armazenamento com ID \"%i\" não é editável pelo usuário", "Personal" : "Pessoal", "System" : "Sistema", "Grant access" : "Permitir acesso", diff --git a/apps/files_external/l10n/pt_BR.json b/apps/files_external/l10n/pt_BR.json index af71fdb1b47..26c20fcb3c1 100644 --- a/apps/files_external/l10n/pt_BR.json +++ b/apps/files_external/l10n/pt_BR.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "Parâmetros de mecanismos de autenticação não satisfeitos", "Insufficient data: %s" : "Dados insuficientes: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Armazenamento com ID \"%i\" não é editável pelo usuário", "Personal" : "Pessoal", "System" : "Sistema", "Grant access" : "Permitir acesso", diff --git a/apps/files_external/l10n/pt_PT.js b/apps/files_external/l10n/pt_PT.js index e80971ccff5..3065f6780af 100644 --- a/apps/files_external/l10n/pt_PT.js +++ b/apps/files_external/l10n/pt_PT.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "Parâmetros do mecanismo de autenticação inválidos", "Insufficient data: %s" : "Dados insuficientes: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Armazenamento com id \"%i\" não é editável pelo utilizador", "Personal" : "Pessoal", "System" : "Sistema", "Grant access" : "Conceder acesso", @@ -63,6 +64,7 @@ OC.L10N.register( "Login credentials" : "Credenciais de login", "Username and password" : "Nome de utilizador e palavra-passe", "Session credentials" : "Credenciais da sessão", + "User provided" : "Utilizador fornecido", "RSA public key" : "Chave pública RSA", "Public key" : "Chave pública", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/pt_PT.json b/apps/files_external/l10n/pt_PT.json index c2a4dd9848d..2525f001dea 100644 --- a/apps/files_external/l10n/pt_PT.json +++ b/apps/files_external/l10n/pt_PT.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "Parâmetros do mecanismo de autenticação inválidos", "Insufficient data: %s" : "Dados insuficientes: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Armazenamento com id \"%i\" não é editável pelo utilizador", "Personal" : "Pessoal", "System" : "Sistema", "Grant access" : "Conceder acesso", @@ -61,6 +62,7 @@ "Login credentials" : "Credenciais de login", "Username and password" : "Nome de utilizador e palavra-passe", "Session credentials" : "Credenciais da sessão", + "User provided" : "Utilizador fornecido", "RSA public key" : "Chave pública RSA", "Public key" : "Chave pública", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/sq.js b/apps/files_external/l10n/sq.js index da6ccf917f5..96438f293bd 100644 --- a/apps/files_external/l10n/sq.js +++ b/apps/files_external/l10n/sq.js @@ -18,6 +18,7 @@ OC.L10N.register( "Unsatisfied authentication mechanism parameters" : "Parametra mekanizmi mirëfilltësimi të papërmbushur", "Insufficient data: %s" : "Të dhëna të pamjaftueshme: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Depozita me id \"%i\" s’është e përpunueshme nga përdoruesi", "Personal" : "Personale", "System" : "Sistem", "Grant access" : "Akordoji hyrje", @@ -62,6 +63,7 @@ OC.L10N.register( "Login credentials" : "Kredenciale hyrjesh", "Username and password" : "Emër përdoruesi dhe fjalëkalim", "Session credentials" : "Kredenciale sesioni", + "User provided" : "Dhënë nga përdoruesi", "RSA public key" : "Kyç publik RSA ", "Public key" : "Kyç publik", "Amazon S3" : "Amazon S3", diff --git a/apps/files_external/l10n/sq.json b/apps/files_external/l10n/sq.json index 068dfd351b5..e3e21598d7a 100644 --- a/apps/files_external/l10n/sq.json +++ b/apps/files_external/l10n/sq.json @@ -16,6 +16,7 @@ "Unsatisfied authentication mechanism parameters" : "Parametra mekanizmi mirëfilltësimi të papërmbushur", "Insufficient data: %s" : "Të dhëna të pamjaftueshme: %s", "%s" : "%s", + "Storage with id \"%i\" is not user editable" : "Depozita me id \"%i\" s’është e përpunueshme nga përdoruesi", "Personal" : "Personale", "System" : "Sistem", "Grant access" : "Akordoji hyrje", @@ -60,6 +61,7 @@ "Login credentials" : "Kredenciale hyrjesh", "Username and password" : "Emër përdoruesi dhe fjalëkalim", "Session credentials" : "Kredenciale sesioni", + "User provided" : "Dhënë nga përdoruesi", "RSA public key" : "Kyç publik RSA ", "Public key" : "Kyç publik", "Amazon S3" : "Amazon S3", diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php index 2dadc0888ec..8fe8991f9c9 100644 --- a/apps/files_sharing/api/share20ocs.php +++ b/apps/files_sharing/api/share20ocs.php @@ -329,9 +329,13 @@ class Share20OCS { return new \OC_OCS_Result($share); } - private function getSharedWithMe() { - $userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, -1, 0); - $groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, -1, 0); + /** + * @param \OCP\Files\File|\OCP\Files\Folder $node + * @return \OC_OCS_Result + */ + private function getSharedWithMe($node = null) { + $userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, -1, 0); + $groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0); $shares = array_merge($userShares, $groupShares); @@ -390,10 +394,6 @@ class Share20OCS { $subfiles = $this->request->getParam('subfiles'); $path = $this->request->getParam('path', null); - if ($sharedWithMe === 'true') { - return $this->getSharedWithMe(); - } - if ($path !== null) { $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID()); try { @@ -403,6 +403,10 @@ class Share20OCS { } } + if ($sharedWithMe === 'true') { + return $this->getSharedWithMe($path); + } + if ($subfiles === 'true') { return $this->getSharesInDir($path); } diff --git a/apps/user_ldap/l10n/he.js b/apps/user_ldap/l10n/he.js index 8b10da2ea1e..9d2fae8295a 100644 --- a/apps/user_ldap/l10n/he.js +++ b/apps/user_ldap/l10n/he.js @@ -17,6 +17,7 @@ OC.L10N.register( "Configuration incomplete" : "הגדרה לא מלאה", "Configuration OK" : "הגדרה בסדר", "Select groups" : "בחירת קבוצות", + "Select object classes" : "בחירת מחלקות עצמים", "Please check the credentials, they seem to be wrong." : "יש לבדוק את פרטי הכניסה, נראה שהם שגויים", "Please specify the port, it could not be auto-detected." : "יש לספק את שער הכניסה - פורט, לא ניתן היה לאתרו בצורה אוטומטית", "Base DN could not be auto-detected, please revise credentials, host and port." : "לא ניתן היה לאתר באופן אוטומטי את בסיס DN, יש להחליף את פרטי הכניסה, פרטי שרת ושער גישה - פורט.", @@ -57,6 +58,7 @@ OC.L10N.register( "Test Configuration" : "בדיקת הגדרות", "Help" : "עזרה", "Groups meeting these criteria are available in %s:" : "קבוצות העומדות בקריטריון זה זמינות ב- %s:", + "Only these object classes:" : "מחלקות עצמים אלו בלבד:", "Only from these groups:" : "רק מקבוצות אלו:", "Search groups" : "חיפוש בקבוצות", "Available groups" : "קבוצות זמינות", @@ -66,23 +68,43 @@ OC.L10N.register( "The filter specifies which LDAP groups shall have access to the %s instance." : "המסנן הקובע לאיזו קבוצת LDAP תהיה יכולת כניסה למקרה %s.", "Verify settings and count groups" : "מאמת הגדרות וסופר קבוצות", "When logging in, %s will find the user based on the following attributes:" : "כאשר מתחברים, %s יחפש את המשתמש על פי המאפיינים הבאים:", + "LDAP / AD Username:" : "שם משתמש LDAP / AD:", + "Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected." : "מאפשר התחברות אל מול שם משתמש LDAP / AD, שהוא רק uid או samaccountname ויזוהה.", + "LDAP / AD Email Address:" : "כתובת דואר אלקטרוני LDAP / AD:", + "Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed." : "מאפשר התחברות אל מול מאפיין דואר אלקטרוני. Mail וכן mailPrimaryAddress יהיו מותרים לשימוש.", + "Other Attributes:" : "מאפיינים נוספים:", + "Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "מגדיר את הסינון הפעיל, כשיש ניסיון התחברות. %%uid מחליף את שם המשתמש בפעולת ההתחברות. לדוגמא: \"uid=%%uid\"", + "Test Loginname" : "בדיקת שם התחברות", + "Verify settings" : "מאמת הגדרות", "1. Server" : "1. שרת", "%s. Server:" : "%s. שרת:", "Add a new and blank configuration" : "הוספת תצורה חדשה וריקה", + "Copy current configuration into new directory binding" : "מעתיק תצורה נוכחית אל תוך תיקייה חדשה", "Delete the current configuration" : "מחיקת תצורה נוכחית", "Host" : "מארח", + "You can omit the protocol, except you require SSL. Then start with ldaps://" : "ניתן להשמיט את הפרוטוקול, אך SSL מחייב. לפיכך יש להתחיל עם ldaps://", "Port" : "פורט", "Detect Port" : "מחיקת שער - פורט", "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 והסיסמא ריקים.", "Password" : "סיסמא", "For anonymous access, leave DN and Password empty." : "לגישה אנונימית, השאר את הDM והסיסמא ריקים.", + "One Base DN per line" : "DN בסיסי אחד לשורה", + "Detect Base DN" : "גילוי DN בסיסי", + "Test Base DN" : "בדיקת DN בסיסי", + "Verify settings and count users" : "מאמת הגדרות וסופר משתמשים", "Saving" : "שמירה", "Back" : "אחורה", "Continue" : "המשך", "LDAP" : "LDAP", "Expert" : "מומחה", "Advanced" : "מתקדם", + "Connection Settings" : "הגדרות התחברות", + "Configuration Active" : "תצורה פעילה", + "When unchecked, this configuration will be skipped." : "כאשר לא מסומן, נדלג על תצורה זו.", + "Disable Main Server" : "ניטרול שרת עיקרי", "in seconds. A change empties the cache." : "בשניות. שינוי מרוקן את המטמון.", + "Directory Settings" : "הגדרות תיקייה", "in bytes" : "בבתים" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_ldap/l10n/he.json b/apps/user_ldap/l10n/he.json index 889a55a7172..c325d8f4405 100644 --- a/apps/user_ldap/l10n/he.json +++ b/apps/user_ldap/l10n/he.json @@ -15,6 +15,7 @@ "Configuration incomplete" : "הגדרה לא מלאה", "Configuration OK" : "הגדרה בסדר", "Select groups" : "בחירת קבוצות", + "Select object classes" : "בחירת מחלקות עצמים", "Please check the credentials, they seem to be wrong." : "יש לבדוק את פרטי הכניסה, נראה שהם שגויים", "Please specify the port, it could not be auto-detected." : "יש לספק את שער הכניסה - פורט, לא ניתן היה לאתרו בצורה אוטומטית", "Base DN could not be auto-detected, please revise credentials, host and port." : "לא ניתן היה לאתר באופן אוטומטי את בסיס DN, יש להחליף את פרטי הכניסה, פרטי שרת ושער גישה - פורט.", @@ -55,6 +56,7 @@ "Test Configuration" : "בדיקת הגדרות", "Help" : "עזרה", "Groups meeting these criteria are available in %s:" : "קבוצות העומדות בקריטריון זה זמינות ב- %s:", + "Only these object classes:" : "מחלקות עצמים אלו בלבד:", "Only from these groups:" : "רק מקבוצות אלו:", "Search groups" : "חיפוש בקבוצות", "Available groups" : "קבוצות זמינות", @@ -64,23 +66,43 @@ "The filter specifies which LDAP groups shall have access to the %s instance." : "המסנן הקובע לאיזו קבוצת LDAP תהיה יכולת כניסה למקרה %s.", "Verify settings and count groups" : "מאמת הגדרות וסופר קבוצות", "When logging in, %s will find the user based on the following attributes:" : "כאשר מתחברים, %s יחפש את המשתמש על פי המאפיינים הבאים:", + "LDAP / AD Username:" : "שם משתמש LDAP / AD:", + "Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected." : "מאפשר התחברות אל מול שם משתמש LDAP / AD, שהוא רק uid או samaccountname ויזוהה.", + "LDAP / AD Email Address:" : "כתובת דואר אלקטרוני LDAP / AD:", + "Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed." : "מאפשר התחברות אל מול מאפיין דואר אלקטרוני. Mail וכן mailPrimaryAddress יהיו מותרים לשימוש.", + "Other Attributes:" : "מאפיינים נוספים:", + "Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" : "מגדיר את הסינון הפעיל, כשיש ניסיון התחברות. %%uid מחליף את שם המשתמש בפעולת ההתחברות. לדוגמא: \"uid=%%uid\"", + "Test Loginname" : "בדיקת שם התחברות", + "Verify settings" : "מאמת הגדרות", "1. Server" : "1. שרת", "%s. Server:" : "%s. שרת:", "Add a new and blank configuration" : "הוספת תצורה חדשה וריקה", + "Copy current configuration into new directory binding" : "מעתיק תצורה נוכחית אל תוך תיקייה חדשה", "Delete the current configuration" : "מחיקת תצורה נוכחית", "Host" : "מארח", + "You can omit the protocol, except you require SSL. Then start with ldaps://" : "ניתן להשמיט את הפרוטוקול, אך SSL מחייב. לפיכך יש להתחיל עם ldaps://", "Port" : "פורט", "Detect Port" : "מחיקת שער - פורט", "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 והסיסמא ריקים.", "Password" : "סיסמא", "For anonymous access, leave DN and Password empty." : "לגישה אנונימית, השאר את הDM והסיסמא ריקים.", + "One Base DN per line" : "DN בסיסי אחד לשורה", + "Detect Base DN" : "גילוי DN בסיסי", + "Test Base DN" : "בדיקת DN בסיסי", + "Verify settings and count users" : "מאמת הגדרות וסופר משתמשים", "Saving" : "שמירה", "Back" : "אחורה", "Continue" : "המשך", "LDAP" : "LDAP", "Expert" : "מומחה", "Advanced" : "מתקדם", + "Connection Settings" : "הגדרות התחברות", + "Configuration Active" : "תצורה פעילה", + "When unchecked, this configuration will be skipped." : "כאשר לא מסומן, נדלג על תצורה זו.", + "Disable Main Server" : "ניטרול שרת עיקרי", "in seconds. A change empties the cache." : "בשניות. שינוי מרוקן את המטמון.", + "Directory Settings" : "הגדרות תיקייה", "in bytes" : "בבתים" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php index 97bb13c5f79..addd7d0b51d 100644 --- a/apps/user_ldap/lib/connection.php +++ b/apps/user_ldap/lib/connection.php @@ -206,7 +206,7 @@ class Connection extends LDAPUtility { } $key = $this->getCacheKey($key); - return json_decode(base64_decode($this->cache->get($key))); + return json_decode(base64_decode($this->cache->get($key)), true); } /** diff --git a/build/integration/features/sharing-v1.feature b/build/integration/features/sharing-v1.feature index dedf2c388fc..bdc1a4224d8 100644 --- a/build/integration/features/sharing-v1.feature +++ b/build/integration/features/sharing-v1.feature @@ -313,6 +313,28 @@ Feature: sharing And the HTTP status code should be "200" And last share_id is included in the answer + Scenario: Sharee can see the filtered share + Given user "user0" exists + And user "user1" exists + And file "textfile0.txt" of user "user0" is shared with user "user1" + And file "textfile1.txt" of user "user0" is shared with user "user1" + And As an "user1" + When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true&path=textfile1 (2).txt" + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And last share_id is included in the answer + + Scenario: Sharee can't see the share that is filtered out + Given user "user0" exists + And user "user1" exists + And file "textfile0.txt" of user "user0" is shared with user "user1" + And file "textfile1.txt" of user "user0" is shared with user "user1" + And As an "user1" + When sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=true&path=textfile0 (2).txt" + Then the OCS status code should be "100" + And the HTTP status code should be "200" + And last share_id is not included in the answer + Scenario: Sharee can see the group share Given As an "admin" And user "user0" exists diff --git a/core/l10n/cs_CZ.js b/core/l10n/cs_CZ.js index 3499635c859..8fcfef6f2b4 100644 --- a/core/l10n/cs_CZ.js +++ b/core/l10n/cs_CZ.js @@ -171,6 +171,7 @@ OC.L10N.register( "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Sdílejte s lidmi na ownClouds použitím syntaxe username@example.com/owncloud", "Share with users or groups …" : "Sdílet s uživateli nebo skupinami", "Share with users, groups or remote users …" : "Sdílet s uživateli, skupinami nebo vzdálenými uživateli", + "Error removing share" : "Chyba při odstraňování sdílení", "Warning" : "Varování", "Error while sending notification" : "Chyba při odesílání upozornění", "Non-existing tag #{tag}" : "Neexistující tag #{tag}", diff --git a/core/l10n/cs_CZ.json b/core/l10n/cs_CZ.json index 09f6b2f0d7b..19c22abd616 100644 --- a/core/l10n/cs_CZ.json +++ b/core/l10n/cs_CZ.json @@ -169,6 +169,7 @@ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Sdílejte s lidmi na ownClouds použitím syntaxe username@example.com/owncloud", "Share with users or groups …" : "Sdílet s uživateli nebo skupinami", "Share with users, groups or remote users …" : "Sdílet s uživateli, skupinami nebo vzdálenými uživateli", + "Error removing share" : "Chyba při odstraňování sdílení", "Warning" : "Varování", "Error while sending notification" : "Chyba při odesílání upozornění", "Non-existing tag #{tag}" : "Neexistující tag #{tag}", diff --git a/core/l10n/fi_FI.js b/core/l10n/fi_FI.js index 392d56b9803..12c131f8410 100644 --- a/core/l10n/fi_FI.js +++ b/core/l10n/fi_FI.js @@ -171,6 +171,7 @@ OC.L10N.register( "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Jaa toisia ownCloud-järjestelmiä käyttävien kesken käyttäen syntaksia käyttäjätunnus@esimerkki.fi/owncloud", "Share with users or groups …" : "Jaa käyttäjien tai ryhmien kanssa…", "Share with users, groups or remote users …" : "Jaa käyttäjien, ryhmien tai etäkäyttäjien kanssa…", + "Error removing share" : "Virhe jakoa poistaessa", "Warning" : "Varoitus", "Error while sending notification" : "Virhe ilmoitusta lähettäessä", "Non-existing tag #{tag}" : "Ei olemassa oleva tunniste #{tag}", diff --git a/core/l10n/fi_FI.json b/core/l10n/fi_FI.json index ecab0feae97..89944f4e153 100644 --- a/core/l10n/fi_FI.json +++ b/core/l10n/fi_FI.json @@ -169,6 +169,7 @@ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Jaa toisia ownCloud-järjestelmiä käyttävien kesken käyttäen syntaksia käyttäjätunnus@esimerkki.fi/owncloud", "Share with users or groups …" : "Jaa käyttäjien tai ryhmien kanssa…", "Share with users, groups or remote users …" : "Jaa käyttäjien, ryhmien tai etäkäyttäjien kanssa…", + "Error removing share" : "Virhe jakoa poistaessa", "Warning" : "Varoitus", "Error while sending notification" : "Virhe ilmoitusta lähettäessä", "Non-existing tag #{tag}" : "Ei olemassa oleva tunniste #{tag}", diff --git a/core/l10n/he.js b/core/l10n/he.js index 7d061d236b5..9a7bfeede44 100644 --- a/core/l10n/he.js +++ b/core/l10n/he.js @@ -119,7 +119,18 @@ OC.L10N.register( "Strong password" : "סיסמא חזקה", "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "שרת האינטרנט שלך אינו מוגדר כהלכה לאפשר סנכרון כיוון שממשק ה־WebDAV כנראה שבור.", "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "שרת האינטרנט שלך לא מוגדר כהלכה לפתור \"{url}\". מידע נוסף קיים <a target=\"_blank\" href=\"{docLink}\">במסמכים</a> שלנו.", + "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "לשרת זה אין חיבור אינטרנט פעיל. לפיכך חלק מהתכונות כגון עגינת אחסון חיצוני, הודעות על עדכונים או התקנת יישומי צד שלישי לא יעבדו. ייתכן ולא יעבדו גם כניסה לקבצים מבחוץ ושליחת הודעות דואר אלקטרוני. אנו ממליצים לאפשר חיבור אינטרנט לשרת זה אם ברצונך שיהיו לך את כל התכונות.", + "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "כנראה וניתן לגשת אל תיקיית data והקבצים שלך מהאינטרנט. קובץ .htaccess אינו עובד. אנו ממליצים בכל תוקף שתגדיר את השרת בצורה כזאת שלא ניתן יהיה לגשת לתיקיית ה- data או להעביר את תיקיית ה- dta מחוץ לנתיב המסמכים של שרת האינטרנט.", + "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "לא הוגדר memory cache. על מנת לשפר את הביצועים יש להגדיר memcache אם קיים. מידע נוסף ניתן לצפות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.", + "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom אינו ניתן לקריאה על ידי PHP אשר אינו מומלץ בשל סיבות אבטחה. מידע נוסף ניתן לראות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.", + "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "גרסת ה- PHP שלך ({version}) אינה <a target=\"_blank\" href=\"{phpLink}\">נתמכת כבר על ידי PHP</a>. אנו ממליצים לשדרג את גרסת ה- PHP ולהנות מהיתרון של עדכוני האבטחה והביצועים שמספק ה- PHP.", + "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "תצורת כותרות פרוקסי ההפוכה אינה נכונה, או שהגישה ל- ownCloud מתבצעת מ- proxy אמין. אם הגישה ל- ownCloud אינה מ- proxy אמין, מדובר בבעיית אבטחה שמאפשרת לתוקף לזיין את כתובת ה- IP כגלויה ל- ownCloud. מידע נוסף ניתן למצוא ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו.", + "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached מוגדר כמטמון מופץ, אבל מותקן מודול PHP לא נכון \"memcache\". רק \\OC\\Memcache\\Memcached תומך ב- \"memcached\" אבל לא ב- \"memcache\". ניתן לצפות ב- <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki בנושא שני המודולים</a>.", + "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "חלק מהקבצים לא עברו את בדיקת התקינות. מידע נוסף איך לפתור את הבעיה ניתן למצוא ב- to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו. (<a href=\"{codeIntegrityDownloadEndpoint}\">רשימה של קבצים לא תקינים…</a> / <a href=\"{rescanEndpoint}\">סריקה מחדש…</a>)", "Error occurred while checking server setup" : "שגיאה אירעה בזמן בדיקת התקנת השרת", + "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "כותרת ה- HTTP \"{header}\" אינה מוגדרת להיות שווה ל- \"{expected}\". הדבר מהווה פוטנציאל סיכון אבטחה או פגיעה בפרטיות ואנו ממליצים לתקן את הגדרה זו.", + "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "כותרת HTTP \"Strict-Transport-Security\" אינה מוגדרת לפחות \"{seconds}\" שניות. להגברת האבטחה אנו ממליצים לאפשר HSTS כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.", + "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "הנך נכנס לאתר באמצעות פרוטוקול HTTP. אנו ממליצים מאוד להגדיר את השרת לעבוד עם פרוטוקול HTTPS במקום כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.", "Shared" : "שותף", "Shared with {recipients}" : "שיתוף עם {recipients}", "Error" : "שגיאה", @@ -153,16 +164,20 @@ OC.L10N.register( "change" : "שינוי", "delete" : "מחיקה", "access control" : "בקרת גישה", + "Could not unshare" : "לא ניתן לבטל שיתוף", "Share details could not be loaded for this item." : "לא ניתן היה לטעון מידע שיתוף לפריט זה", "An error occured. Please try again" : "אירעה שגיאה. יש לנסות בבקשה שוב", "Share" : "שתף", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "ניתן לשתף עם אנשים אחרים המשתמשים ב- ownClouds בעזרת הפורמט הבא username@example.com/owncloud", "Share with users or groups …" : "שיתוף עם משתמשים או קבוצות...", "Share with users, groups or remote users …" : "שיתוף עם משתמשים, קבוצות או משתמשים חצוניים...", + "Error removing share" : "שגיאה בזמן הסרת שיתוף", "Warning" : "אזהרה", "Error while sending notification" : "שגיאה בזמן שליחת הודעה", "Non-existing tag #{tag}" : "תגית לא קיימת #{tag}", + "not assignable" : "לא ניתן להקצאה", "invisible" : "בלתי גלוי", + "({scope})" : "({scope})", "Delete" : "מחיקה", "Rename" : "שינוי שם", "Global tags" : "תגיות גלובליות", @@ -179,6 +194,8 @@ OC.L10N.register( "Hello {name}" : "שלום {name}", "_download %n file_::_download %n files_" : ["הורד %n קובץ","הורדו %n קבצים"], "{version} is available. Get more information on how to update." : "{version} זמינה. ניתן לקבל מידע נוסף על איך לעדכן.", + "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "מתבצע עכשיו שדרוג, מעבר מדף זה עלול לפגוע בתהליך בסביבות הפעלה מסויימות.", + "Updating {productName} to version {version}, this may take a while." : "מעדכן {productName} לגרסה {version}, זה יקח זמן מה.", "An error occurred." : "אירעה שגיאה.", "Please reload the page." : "יש להעלות מחדש דף זה.", "The update was unsuccessful. " : "העדכון בוצע בהצלחה.", @@ -186,6 +203,7 @@ OC.L10N.register( "The update was successful. Redirecting you to ownCloud now." : "תהליך העדכון הסתיים בהצלחה. עכשיו מנתב אותך אל ownCloud.", "Searching other places" : "מחפש במקומות אחרים", "No search results in other folders" : "אין תוצאות חיפוש בתיקיות אחרות", + "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} תוצאת חיפוש בתיקייה אחרות","{count} תוצאות חיפוש בתיקיות אחרות"], "Personal" : "אישי", "Users" : "משתמשים", "Apps" : "יישומים", @@ -206,6 +224,9 @@ OC.L10N.register( "The share will expire on %s." : "השיתוף יפוג תוקף ב- %s.", "Cheers!" : "לחיים!", "Internal Server Error" : "שגיאה פנימית בשרת", + "The server encountered an internal error and was unable to complete your request." : "השרת נתקל בשגיאה פנימית ולא הצליח לסיים את הבקשה שלך.", + "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "יש ליצור קשר עם מנהל השרת אם שגיאה זו חוזרת מספר פעמים, יש לצרף לדיווח את הפרטים הטכניים למטה.", + "More details can be found in the server log." : "פרטים נוספים ניתן למצוא בלוג של הרשת.", "Technical details" : "פרטים טכנים", "Remote Address: %s" : "כתובת מרוחקת: %s", "Request ID: %s" : "מספר זיהוי מבוקש: %s", @@ -217,24 +238,38 @@ OC.L10N.register( "Trace" : "עקבות", "Security warning" : "אזהרת אבטחה", "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "תיקיית וקבצי המידע שלך כנראה נגישים מהאינטרנט מכיוון שקובץ ה.htaccess לא עובד.", + "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "למידע איך להגדיר את השרת שלך, ניתן לראות ב- <a href=\"%s\" target=\"_blank\">מסמכי התיעוד</a>.", "Create an <strong>admin account</strong>" : "יצירת <strong>חשבון מנהל</strong>", "Username" : "שם משתמש", "Storage & database" : "אחסון ומסד נתונים", "Data folder" : "תיקיית נתונים", "Configure the database" : "הגדרת מסד הנתונים", "Only %s is available." : "רק %s זמין.", + "Install and activate additional PHP modules to choose other database types." : "לבחירת סוגים אחרים של מסדי נתונים יש להתקין ולהפעיל מודולי PHP נוספים.", + "For more details check out the documentation." : "למידע נוסף יש לבדוק במסמכי התיעוד.", "Database user" : "שם משתמש במסד הנתונים", "Database password" : "ססמת מסד הנתונים", "Database name" : "שם מסד הנתונים", "Database tablespace" : "מרחב הכתובות של מסד הנתונים", "Database host" : "שרת בסיס נתונים", + "Performance warning" : "אזהרת ביצועים", + "SQLite will be used as database." : "יעשה שימוש ב- SQLite כמסד נתונים.", + "For larger installations we recommend to choose a different database backend." : "להתקנות נרחבות אנו ממליצים לבחור מסד נתונים אחר לצד השרת.", "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "במיוחד כאשר משתמשים במחשב שולחני לסנכרון קבצים השימוש ב SQLite אינו מומלץ.", "Finish setup" : "סיום התקנה", "Finishing …" : "מסיים...", "Need help?" : "עזרה נזקקת?", + "See the documentation" : "יש לצפות במסמכי התיעוד", + "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "הי לך,<br><br>כדאי לך לדעת ש- %s משתף/פת <strong>%s</strong> אתך.<br><a href=\"%s\">לצפייה!</a><br><br>", + "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "יישום זה דורש JavaScript לפעולה נכונה. יש {linkstart}לאפשר JavaScript{linkend} ולטעון את העמוד מחדש.", "Log out" : "התנתקות", "Search" : "חיפוש", + "Server side authentication failed!" : "אימות לצד שרת נכשל!", + "Please contact your administrator." : "יש ליצור קשר עם המנהל.", + "An internal error occured." : "שגיאה פנימית אירעה.", + "Please try again or contact your administrator." : "יש לנסות שוב ליצור קשר עם המנהל שלך.", "Log in" : "כניסה", + "Wrong password. Reset it?" : "סיסמא שגוייה. האם לאפס אותה?", "Wrong password." : "סיסמא שגוייה.", "Stay logged in" : "השאר מחובר", "Alternative Logins" : "כניסות אלטרנטיביות", @@ -242,7 +277,23 @@ OC.L10N.register( "New password" : "ססמה חדשה", "New Password" : "סיסמא חדשה", "Reset password" : "איפוס ססמה", + "This ownCloud instance is currently in single user mode." : "הפעלת ownCloud זו עובדת כרגע במצב של משתמש יחיד.", + "This means only administrators can use the instance." : "לפיכך רק מנהלים יכולים להשתמש בהפעלה זו.", + "Contact your system administrator if this message persists or appeared unexpectedly." : "יש ליצור קשר עם מנהל המערכת אם הודעה שו נמשכת או מופיעה באופן בלתי צפוי. ", "Thank you for your patience." : "תודה על הסבלנות.", - "Start update" : "התחלת עדכון" + "You are accessing the server from an untrusted domain." : "נכנסת לשרת משם מתחם / דומיין שאינו מהימן.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "יש ליצור קשר עם המנהל שלך. אם הנך המנהל של הפעלה זו, יש להגדיר את הגדרות ה- \"trusted_domains\" של config/config.php. דוגמת תצורה ניתן לראות ב- config/config.sample.php.", + "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "בהתאם לתצורה שלך, כמנהל יתכן ותוכל להשתמש בכפתור מטה להפיכת שם המתחם / דומיין למהימן.", + "Add \"%s\" as trusted domain" : "הוספת \"%s\" כשם מתחם / דומיין מהימן", + "App update required" : "נדרש עדכון יישום", + "%s will be updated to version %s" : "%s יעודכן לגרסה %s", + "These apps will be updated:" : "יישומים אלו יעודכנו:", + "These incompatible apps will be disabled:" : "יישומים לא תואמים ינוטרלו:", + "The theme %s has been disabled." : "ערכת הנושא %s נוטרלה.", + "Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "יש לוודא שמסד הנתונים, תיקיית config ותיקיית data גובו לפני ההמשך.", + "Start update" : "התחלת עדכון", + "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "למניעת פסקי זמן בהתקנות גדולות, ניתן במקום להריץ את הפקודה הבאה בתיקיית ההתקנה שלך:", + "This %s instance is currently in maintenance mode, which may take a while." : "הפעלה %s זו כרגע במצב אחזקה, שתמשך זמן מה.", + "This page will refresh itself when the %s instance is available again." : "עמוד זה ירענן את עצמו כשהפעלת %s תהיה זמינה שוב." }, "nplurals=2; plural=(n != 1);"); diff --git a/core/l10n/he.json b/core/l10n/he.json index 64492bcbcac..9e25f9895d1 100644 --- a/core/l10n/he.json +++ b/core/l10n/he.json @@ -117,7 +117,18 @@ "Strong password" : "סיסמא חזקה", "Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken." : "שרת האינטרנט שלך אינו מוגדר כהלכה לאפשר סנכרון כיוון שממשק ה־WebDAV כנראה שבור.", "Your web server is not set up properly to resolve \"{url}\". Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "שרת האינטרנט שלך לא מוגדר כהלכה לפתור \"{url}\". מידע נוסף קיים <a target=\"_blank\" href=\"{docLink}\">במסמכים</a> שלנו.", + "This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features." : "לשרת זה אין חיבור אינטרנט פעיל. לפיכך חלק מהתכונות כגון עגינת אחסון חיצוני, הודעות על עדכונים או התקנת יישומי צד שלישי לא יעבדו. ייתכן ולא יעבדו גם כניסה לקבצים מבחוץ ושליחת הודעות דואר אלקטרוני. אנו ממליצים לאפשר חיבור אינטרנט לשרת זה אם ברצונך שיהיו לך את כל התכונות.", + "Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root." : "כנראה וניתן לגשת אל תיקיית data והקבצים שלך מהאינטרנט. קובץ .htaccess אינו עובד. אנו ממליצים בכל תוקף שתגדיר את השרת בצורה כזאת שלא ניתן יהיה לגשת לתיקיית ה- data או להעביר את תיקיית ה- dta מחוץ לנתיב המסמכים של שרת האינטרנט.", + "No memory cache has been configured. To enhance your performance please configure a memcache if available. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "לא הוגדר memory cache. על מנת לשפר את הביצועים יש להגדיר memcache אם קיים. מידע נוסף ניתן לצפות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.", + "/dev/urandom is not readable by PHP which is highly discouraged for security reasons. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "/dev/urandom אינו ניתן לקריאה על ידי PHP אשר אינו מומלץ בשל סיבות אבטחה. מידע נוסף ניתן לראות ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a>.", + "Your PHP version ({version}) is no longer <a target=\"_blank\" href=\"{phpLink}\">supported by PHP</a>. We encourage you to upgrade your PHP version to take advantage of performance and security updates provided by PHP." : "גרסת ה- PHP שלך ({version}) אינה <a target=\"_blank\" href=\"{phpLink}\">נתמכת כבר על ידי PHP</a>. אנו ממליצים לשדרג את גרסת ה- PHP ולהנות מהיתרון של עדכוני האבטחה והביצועים שמספק ה- PHP.", + "The reverse proxy headers configuration is incorrect, or you are accessing ownCloud from a trusted proxy. If you are not accessing ownCloud from a trusted proxy, this is a security issue and can allow an attacker to spoof their IP address as visible to ownCloud. Further information can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>." : "תצורת כותרות פרוקסי ההפוכה אינה נכונה, או שהגישה ל- ownCloud מתבצעת מ- proxy אמין. אם הגישה ל- ownCloud אינה מ- proxy אמין, מדובר בבעיית אבטחה שמאפשרת לתוקף לזיין את כתובת ה- IP כגלויה ל- ownCloud. מידע נוסף ניתן למצוא ב- <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו.", + "Memcached is configured as distributed cache, but the wrong PHP module \"memcache\" is installed. \\OC\\Memcache\\Memcached only supports \"memcached\" and not \"memcache\". See the <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki about both modules</a>." : "Memcached מוגדר כמטמון מופץ, אבל מותקן מודול PHP לא נכון \"memcache\". רק \\OC\\Memcache\\Memcached תומך ב- \"memcached\" אבל לא ב- \"memcache\". ניתן לצפות ב- <a target=\"_blank\" href=\"{wikiLink}\">memcached wiki בנושא שני המודולים</a>.", + "Some files have not passed the integrity check. Further information on how to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">documentation</a>. (<a href=\"{codeIntegrityDownloadEndpoint}\">List of invalid files…</a> / <a href=\"{rescanEndpoint}\">Rescan…</a>)" : "חלק מהקבצים לא עברו את בדיקת התקינות. מידע נוסף איך לפתור את הבעיה ניתן למצוא ב- to resolve this issue can be found in our <a target=\"_blank\" href=\"{docLink}\">מסמכי התיעוד</a> שלנו. (<a href=\"{codeIntegrityDownloadEndpoint}\">רשימה של קבצים לא תקינים…</a> / <a href=\"{rescanEndpoint}\">סריקה מחדש…</a>)", "Error occurred while checking server setup" : "שגיאה אירעה בזמן בדיקת התקנת השרת", + "The \"{header}\" HTTP header is not configured to equal to \"{expected}\". This is a potential security or privacy risk and we recommend adjusting this setting." : "כותרת ה- HTTP \"{header}\" אינה מוגדרת להיות שווה ל- \"{expected}\". הדבר מהווה פוטנציאל סיכון אבטחה או פגיעה בפרטיות ואנו ממליצים לתקן את הגדרה זו.", + "The \"Strict-Transport-Security\" HTTP header is not configured to least \"{seconds}\" seconds. For enhanced security we recommend enabling HSTS as described in our <a href=\"{docUrl}\">security tips</a>." : "כותרת HTTP \"Strict-Transport-Security\" אינה מוגדרת לפחות \"{seconds}\" שניות. להגברת האבטחה אנו ממליצים לאפשר HSTS כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.", + "You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead as described in our <a href=\"{docUrl}\">security tips</a>." : "הנך נכנס לאתר באמצעות פרוטוקול HTTP. אנו ממליצים מאוד להגדיר את השרת לעבוד עם פרוטוקול HTTPS במקום כפי שמוסבר ב- <a href=\"{docUrl}\">טיפים לאבטחה</a> שלנו.", "Shared" : "שותף", "Shared with {recipients}" : "שיתוף עם {recipients}", "Error" : "שגיאה", @@ -151,16 +162,20 @@ "change" : "שינוי", "delete" : "מחיקה", "access control" : "בקרת גישה", + "Could not unshare" : "לא ניתן לבטל שיתוף", "Share details could not be loaded for this item." : "לא ניתן היה לטעון מידע שיתוף לפריט זה", "An error occured. Please try again" : "אירעה שגיאה. יש לנסות בבקשה שוב", "Share" : "שתף", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "ניתן לשתף עם אנשים אחרים המשתמשים ב- ownClouds בעזרת הפורמט הבא username@example.com/owncloud", "Share with users or groups …" : "שיתוף עם משתמשים או קבוצות...", "Share with users, groups or remote users …" : "שיתוף עם משתמשים, קבוצות או משתמשים חצוניים...", + "Error removing share" : "שגיאה בזמן הסרת שיתוף", "Warning" : "אזהרה", "Error while sending notification" : "שגיאה בזמן שליחת הודעה", "Non-existing tag #{tag}" : "תגית לא קיימת #{tag}", + "not assignable" : "לא ניתן להקצאה", "invisible" : "בלתי גלוי", + "({scope})" : "({scope})", "Delete" : "מחיקה", "Rename" : "שינוי שם", "Global tags" : "תגיות גלובליות", @@ -177,6 +192,8 @@ "Hello {name}" : "שלום {name}", "_download %n file_::_download %n files_" : ["הורד %n קובץ","הורדו %n קבצים"], "{version} is available. Get more information on how to update." : "{version} זמינה. ניתן לקבל מידע נוסף על איך לעדכן.", + "The upgrade is in progress, leaving this page might interrupt the process in some environments." : "מתבצע עכשיו שדרוג, מעבר מדף זה עלול לפגוע בתהליך בסביבות הפעלה מסויימות.", + "Updating {productName} to version {version}, this may take a while." : "מעדכן {productName} לגרסה {version}, זה יקח זמן מה.", "An error occurred." : "אירעה שגיאה.", "Please reload the page." : "יש להעלות מחדש דף זה.", "The update was unsuccessful. " : "העדכון בוצע בהצלחה.", @@ -184,6 +201,7 @@ "The update was successful. Redirecting you to ownCloud now." : "תהליך העדכון הסתיים בהצלחה. עכשיו מנתב אותך אל ownCloud.", "Searching other places" : "מחפש במקומות אחרים", "No search results in other folders" : "אין תוצאות חיפוש בתיקיות אחרות", + "_{count} search result in another folder_::_{count} search results in other folders_" : ["{count} תוצאת חיפוש בתיקייה אחרות","{count} תוצאות חיפוש בתיקיות אחרות"], "Personal" : "אישי", "Users" : "משתמשים", "Apps" : "יישומים", @@ -204,6 +222,9 @@ "The share will expire on %s." : "השיתוף יפוג תוקף ב- %s.", "Cheers!" : "לחיים!", "Internal Server Error" : "שגיאה פנימית בשרת", + "The server encountered an internal error and was unable to complete your request." : "השרת נתקל בשגיאה פנימית ולא הצליח לסיים את הבקשה שלך.", + "Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report." : "יש ליצור קשר עם מנהל השרת אם שגיאה זו חוזרת מספר פעמים, יש לצרף לדיווח את הפרטים הטכניים למטה.", + "More details can be found in the server log." : "פרטים נוספים ניתן למצוא בלוג של הרשת.", "Technical details" : "פרטים טכנים", "Remote Address: %s" : "כתובת מרוחקת: %s", "Request ID: %s" : "מספר זיהוי מבוקש: %s", @@ -215,24 +236,38 @@ "Trace" : "עקבות", "Security warning" : "אזהרת אבטחה", "Your data directory and files are probably accessible from the internet because the .htaccess file does not work." : "תיקיית וקבצי המידע שלך כנראה נגישים מהאינטרנט מכיוון שקובץ ה.htaccess לא עובד.", + "For information how to properly configure your server, please see the <a href=\"%s\" target=\"_blank\">documentation</a>." : "למידע איך להגדיר את השרת שלך, ניתן לראות ב- <a href=\"%s\" target=\"_blank\">מסמכי התיעוד</a>.", "Create an <strong>admin account</strong>" : "יצירת <strong>חשבון מנהל</strong>", "Username" : "שם משתמש", "Storage & database" : "אחסון ומסד נתונים", "Data folder" : "תיקיית נתונים", "Configure the database" : "הגדרת מסד הנתונים", "Only %s is available." : "רק %s זמין.", + "Install and activate additional PHP modules to choose other database types." : "לבחירת סוגים אחרים של מסדי נתונים יש להתקין ולהפעיל מודולי PHP נוספים.", + "For more details check out the documentation." : "למידע נוסף יש לבדוק במסמכי התיעוד.", "Database user" : "שם משתמש במסד הנתונים", "Database password" : "ססמת מסד הנתונים", "Database name" : "שם מסד הנתונים", "Database tablespace" : "מרחב הכתובות של מסד הנתונים", "Database host" : "שרת בסיס נתונים", + "Performance warning" : "אזהרת ביצועים", + "SQLite will be used as database." : "יעשה שימוש ב- SQLite כמסד נתונים.", + "For larger installations we recommend to choose a different database backend." : "להתקנות נרחבות אנו ממליצים לבחור מסד נתונים אחר לצד השרת.", "Especially when using the desktop client for file syncing the use of SQLite is discouraged." : "במיוחד כאשר משתמשים במחשב שולחני לסנכרון קבצים השימוש ב SQLite אינו מומלץ.", "Finish setup" : "סיום התקנה", "Finishing …" : "מסיים...", "Need help?" : "עזרה נזקקת?", + "See the documentation" : "יש לצפות במסמכי התיעוד", + "Hey there,<br><br>just letting you know that %s shared <strong>%s</strong> with you.<br><a href=\"%s\">View it!</a><br><br>" : "הי לך,<br><br>כדאי לך לדעת ש- %s משתף/פת <strong>%s</strong> אתך.<br><a href=\"%s\">לצפייה!</a><br><br>", + "This application requires JavaScript for correct operation. Please {linkstart}enable JavaScript{linkend} and reload the page." : "יישום זה דורש JavaScript לפעולה נכונה. יש {linkstart}לאפשר JavaScript{linkend} ולטעון את העמוד מחדש.", "Log out" : "התנתקות", "Search" : "חיפוש", + "Server side authentication failed!" : "אימות לצד שרת נכשל!", + "Please contact your administrator." : "יש ליצור קשר עם המנהל.", + "An internal error occured." : "שגיאה פנימית אירעה.", + "Please try again or contact your administrator." : "יש לנסות שוב ליצור קשר עם המנהל שלך.", "Log in" : "כניסה", + "Wrong password. Reset it?" : "סיסמא שגוייה. האם לאפס אותה?", "Wrong password." : "סיסמא שגוייה.", "Stay logged in" : "השאר מחובר", "Alternative Logins" : "כניסות אלטרנטיביות", @@ -240,7 +275,23 @@ "New password" : "ססמה חדשה", "New Password" : "סיסמא חדשה", "Reset password" : "איפוס ססמה", + "This ownCloud instance is currently in single user mode." : "הפעלת ownCloud זו עובדת כרגע במצב של משתמש יחיד.", + "This means only administrators can use the instance." : "לפיכך רק מנהלים יכולים להשתמש בהפעלה זו.", + "Contact your system administrator if this message persists or appeared unexpectedly." : "יש ליצור קשר עם מנהל המערכת אם הודעה שו נמשכת או מופיעה באופן בלתי צפוי. ", "Thank you for your patience." : "תודה על הסבלנות.", - "Start update" : "התחלת עדכון" + "You are accessing the server from an untrusted domain." : "נכנסת לשרת משם מתחם / דומיין שאינו מהימן.", + "Please contact your administrator. If you are an administrator of this instance, configure the \"trusted_domains\" setting in config/config.php. An example configuration is provided in config/config.sample.php." : "יש ליצור קשר עם המנהל שלך. אם הנך המנהל של הפעלה זו, יש להגדיר את הגדרות ה- \"trusted_domains\" של config/config.php. דוגמת תצורה ניתן לראות ב- config/config.sample.php.", + "Depending on your configuration, as an administrator you might also be able to use the button below to trust this domain." : "בהתאם לתצורה שלך, כמנהל יתכן ותוכל להשתמש בכפתור מטה להפיכת שם המתחם / דומיין למהימן.", + "Add \"%s\" as trusted domain" : "הוספת \"%s\" כשם מתחם / דומיין מהימן", + "App update required" : "נדרש עדכון יישום", + "%s will be updated to version %s" : "%s יעודכן לגרסה %s", + "These apps will be updated:" : "יישומים אלו יעודכנו:", + "These incompatible apps will be disabled:" : "יישומים לא תואמים ינוטרלו:", + "The theme %s has been disabled." : "ערכת הנושא %s נוטרלה.", + "Please make sure that the database, the config folder and the data folder have been backed up before proceeding." : "יש לוודא שמסד הנתונים, תיקיית config ותיקיית data גובו לפני ההמשך.", + "Start update" : "התחלת עדכון", + "To avoid timeouts with larger installations, you can instead run the following command from your installation directory:" : "למניעת פסקי זמן בהתקנות גדולות, ניתן במקום להריץ את הפקודה הבאה בתיקיית ההתקנה שלך:", + "This %s instance is currently in maintenance mode, which may take a while." : "הפעלה %s זו כרגע במצב אחזקה, שתמשך זמן מה.", + "This page will refresh itself when the %s instance is available again." : "עמוד זה ירענן את עצמו כשהפעלת %s תהיה זמינה שוב." },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/core/l10n/it.js b/core/l10n/it.js index 59c1c16db74..d23609d57ec 100644 --- a/core/l10n/it.js +++ b/core/l10n/it.js @@ -171,6 +171,7 @@ OC.L10N.register( "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Condividi con persone su altri ownCloud utilizzando la sintassi nomeutente@esempio.com/owncloud", "Share with users or groups …" : "Condividi con utenti o gruppi...", "Share with users, groups or remote users …" : "Condividi con utenti, gruppi o utenti remoti...", + "Error removing share" : "Errore durante la rimozione della condivisione", "Warning" : "Avviso", "Error while sending notification" : "Errore durante l'invio della notifica", "Non-existing tag #{tag}" : "Tag #{tag} inesistente", diff --git a/core/l10n/it.json b/core/l10n/it.json index 821b3cc18e7..966d0f58125 100644 --- a/core/l10n/it.json +++ b/core/l10n/it.json @@ -169,6 +169,7 @@ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Condividi con persone su altri ownCloud utilizzando la sintassi nomeutente@esempio.com/owncloud", "Share with users or groups …" : "Condividi con utenti o gruppi...", "Share with users, groups or remote users …" : "Condividi con utenti, gruppi o utenti remoti...", + "Error removing share" : "Errore durante la rimozione della condivisione", "Warning" : "Avviso", "Error while sending notification" : "Errore durante l'invio della notifica", "Non-existing tag #{tag}" : "Tag #{tag} inesistente", diff --git a/core/l10n/ja.js b/core/l10n/ja.js index 044ca97e888..1b368469f43 100644 --- a/core/l10n/ja.js +++ b/core/l10n/ja.js @@ -163,17 +163,21 @@ OC.L10N.register( "change" : "更新", "delete" : "削除", "access control" : "アクセス権限", + "Could not unshare" : "共有の解除ができませんでした", "Share details could not be loaded for this item." : "共有の詳細はこのアイテムによりロードできませんでした。", "An error occured. Please try again" : "エラーが発生しました。もう一度トライしてください。", "Share" : "共有", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "次の形式で指定して他のownCloudのユーザーと、共有", "Share with users or groups …" : "ユーザーもしくはグループと共有 ...", "Share with users, groups or remote users …" : "ユーザー、グループもしくはリモートユーザーと共有 ...", + "Error removing share" : "共有の削除エラー", "Warning" : "警告", "Error while sending notification" : "通知送信中にエラーが発生", "Non-existing tag #{tag}" : "存在しないタグ#{tag}", + "not assignable" : "割り当てできない", "Delete" : "削除", "Rename" : "名前の変更", + "Global tags" : "グローバルタグ", "The object type is not specified." : "オブジェクトタイプが指定されていません。", "Enter new" : "新規に入力", "Add" : "追加", diff --git a/core/l10n/ja.json b/core/l10n/ja.json index 337aa886031..4dbcaac6a08 100644 --- a/core/l10n/ja.json +++ b/core/l10n/ja.json @@ -161,17 +161,21 @@ "change" : "更新", "delete" : "削除", "access control" : "アクセス権限", + "Could not unshare" : "共有の解除ができませんでした", "Share details could not be loaded for this item." : "共有の詳細はこのアイテムによりロードできませんでした。", "An error occured. Please try again" : "エラーが発生しました。もう一度トライしてください。", "Share" : "共有", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "次の形式で指定して他のownCloudのユーザーと、共有", "Share with users or groups …" : "ユーザーもしくはグループと共有 ...", "Share with users, groups or remote users …" : "ユーザー、グループもしくはリモートユーザーと共有 ...", + "Error removing share" : "共有の削除エラー", "Warning" : "警告", "Error while sending notification" : "通知送信中にエラーが発生", "Non-existing tag #{tag}" : "存在しないタグ#{tag}", + "not assignable" : "割り当てできない", "Delete" : "削除", "Rename" : "名前の変更", + "Global tags" : "グローバルタグ", "The object type is not specified." : "オブジェクトタイプが指定されていません。", "Enter new" : "新規に入力", "Add" : "追加", diff --git a/core/l10n/nl.js b/core/l10n/nl.js index ed533d6d31c..560cdbcebbc 100644 --- a/core/l10n/nl.js +++ b/core/l10n/nl.js @@ -164,17 +164,20 @@ OC.L10N.register( "change" : "wijzig", "delete" : "verwijderen", "access control" : "toegangscontrole", + "Could not unshare" : "Kon delen niet ongedaan maken", "Share details could not be loaded for this item." : "Details van shares voor dit object konden niet worden geladen.", "An error occured. Please try again" : "Er trad een fout op. Probeer het opnieuw", "Share" : "Delen", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Delen met mensen op andere ownClouds via de syntax gebruikersnaam@voorbeeld.org/owncloud", "Share with users or groups …" : "Delen met gebruikers of groepen ...", "Share with users, groups or remote users …" : "Delen met gebruikers, groepen of externe gebruikers ...", + "Error removing share" : "Fout bij verwijderen share", "Warning" : "Waarschuwing", "Error while sending notification" : "Fout bij versturen melding", "Non-existing tag #{tag}" : "Niet bestaande tag #{tag}", "not assignable" : "niet toewijsbaar", "invisible" : "onzichtbaar", + "({scope})" : "({scope})", "Delete" : "Verwijder", "Rename" : "Naam wijzigen", "Global tags" : "Globale tags", diff --git a/core/l10n/nl.json b/core/l10n/nl.json index 906e1d23278..f5eb1c59b41 100644 --- a/core/l10n/nl.json +++ b/core/l10n/nl.json @@ -162,17 +162,20 @@ "change" : "wijzig", "delete" : "verwijderen", "access control" : "toegangscontrole", + "Could not unshare" : "Kon delen niet ongedaan maken", "Share details could not be loaded for this item." : "Details van shares voor dit object konden niet worden geladen.", "An error occured. Please try again" : "Er trad een fout op. Probeer het opnieuw", "Share" : "Delen", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Delen met mensen op andere ownClouds via de syntax gebruikersnaam@voorbeeld.org/owncloud", "Share with users or groups …" : "Delen met gebruikers of groepen ...", "Share with users, groups or remote users …" : "Delen met gebruikers, groepen of externe gebruikers ...", + "Error removing share" : "Fout bij verwijderen share", "Warning" : "Waarschuwing", "Error while sending notification" : "Fout bij versturen melding", "Non-existing tag #{tag}" : "Niet bestaande tag #{tag}", "not assignable" : "niet toewijsbaar", "invisible" : "onzichtbaar", + "({scope})" : "({scope})", "Delete" : "Verwijder", "Rename" : "Naam wijzigen", "Global tags" : "Globale tags", diff --git a/core/l10n/pt_BR.js b/core/l10n/pt_BR.js index ec0605eaace..3d4e236bac2 100644 --- a/core/l10n/pt_BR.js +++ b/core/l10n/pt_BR.js @@ -164,17 +164,20 @@ OC.L10N.register( "change" : "mudança", "delete" : "remover", "access control" : "controle de acesso", + "Could not unshare" : "Não foi possível descompartilhar", "Share details could not be loaded for this item." : "Detalhes de compartilhamento não puderam ser carregados para este item.", "An error occured. Please try again" : "Ocorreu um erro. Por favor tente novamente", "Share" : "Compartilhar", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhar com usuários em outros ownClouds usando a sintaxe username@example.com/owncloud", "Share with users or groups …" : "Compartilhar com usuários ou grupos ...", "Share with users, groups or remote users …" : "Compartilhar com usuários, grupos ou usuários remoto ...", + "Error removing share" : "Erro na remoção do compartilhamento", "Warning" : "Aviso", "Error while sending notification" : "Erro ao enviar notificação", "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}", "not assignable" : "não atribuível", "invisible" : "invisível", + "({scope})" : "({scope})", "Delete" : "Eliminar", "Rename" : "Renomear", "Global tags" : "Etiquetas Globais", diff --git a/core/l10n/pt_BR.json b/core/l10n/pt_BR.json index eb0e5c223cb..f2289975685 100644 --- a/core/l10n/pt_BR.json +++ b/core/l10n/pt_BR.json @@ -162,17 +162,20 @@ "change" : "mudança", "delete" : "remover", "access control" : "controle de acesso", + "Could not unshare" : "Não foi possível descompartilhar", "Share details could not be loaded for this item." : "Detalhes de compartilhamento não puderam ser carregados para este item.", "An error occured. Please try again" : "Ocorreu um erro. Por favor tente novamente", "Share" : "Compartilhar", "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhar com usuários em outros ownClouds usando a sintaxe username@example.com/owncloud", "Share with users or groups …" : "Compartilhar com usuários ou grupos ...", "Share with users, groups or remote users …" : "Compartilhar com usuários, grupos ou usuários remoto ...", + "Error removing share" : "Erro na remoção do compartilhamento", "Warning" : "Aviso", "Error while sending notification" : "Erro ao enviar notificação", "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}", "not assignable" : "não atribuível", "invisible" : "invisível", + "({scope})" : "({scope})", "Delete" : "Eliminar", "Rename" : "Renomear", "Global tags" : "Etiquetas Globais", diff --git a/core/l10n/pt_PT.js b/core/l10n/pt_PT.js index 5f5ae5a47bf..653ec6ec8b5 100644 --- a/core/l10n/pt_PT.js +++ b/core/l10n/pt_PT.js @@ -171,6 +171,7 @@ OC.L10N.register( "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhe com as pessoas nas outras ownClouds utilizando a sintaxe username@example.com/owncloud", "Share with users or groups …" : "Partilhar com utilizadores ou grupos...", "Share with users, groups or remote users …" : "Partilhar com utilizadores, grupos ou utilizadores remotos...", + "Error removing share" : "Erro ao remover partilha", "Warning" : "Aviso", "Error while sending notification" : "Erro enquanto estava a enviar a notificação", "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}", diff --git a/core/l10n/pt_PT.json b/core/l10n/pt_PT.json index 0ef5974413a..af02e2bf081 100644 --- a/core/l10n/pt_PT.json +++ b/core/l10n/pt_PT.json @@ -169,6 +169,7 @@ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Compartilhe com as pessoas nas outras ownClouds utilizando a sintaxe username@example.com/owncloud", "Share with users or groups …" : "Partilhar com utilizadores ou grupos...", "Share with users, groups or remote users …" : "Partilhar com utilizadores, grupos ou utilizadores remotos...", + "Error removing share" : "Erro ao remover partilha", "Warning" : "Aviso", "Error while sending notification" : "Erro enquanto estava a enviar a notificação", "Non-existing tag #{tag}" : "Etiqueta não existente #{tag}", diff --git a/core/l10n/sq.js b/core/l10n/sq.js index 695f90f53b1..bcdec3b9c73 100644 --- a/core/l10n/sq.js +++ b/core/l10n/sq.js @@ -171,6 +171,7 @@ OC.L10N.register( "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Ndajeni me persona në ownCloud-e të tjera duke përdorur sintaksën username@example.com/owncloud", "Share with users or groups …" : "Ndajeni me përdorues ose grupe …", "Share with users, groups or remote users …" : "Ndajeni me përdorues, grupe ose përdorues të largët …", + "Error removing share" : "Gabim në heqjen e ndarjes", "Warning" : "Kujdes", "Error while sending notification" : "Gabim gjatë dërgimit të njoftimit", "Non-existing tag #{tag}" : "Etiketë #{tag} që s’ekziston", diff --git a/core/l10n/sq.json b/core/l10n/sq.json index 8be7e771136..3fdd04bd429 100644 --- a/core/l10n/sq.json +++ b/core/l10n/sq.json @@ -169,6 +169,7 @@ "Share with people on other ownClouds using the syntax username@example.com/owncloud" : "Ndajeni me persona në ownCloud-e të tjera duke përdorur sintaksën username@example.com/owncloud", "Share with users or groups …" : "Ndajeni me përdorues ose grupe …", "Share with users, groups or remote users …" : "Ndajeni me përdorues, grupe ose përdorues të largët …", + "Error removing share" : "Gabim në heqjen e ndarjes", "Warning" : "Kujdes", "Error while sending notification" : "Gabim gjatë dërgimit të njoftimit", "Non-existing tag #{tag}" : "Etiketë #{tag} që s’ekziston", diff --git a/lib/l10n/ja.js b/lib/l10n/ja.js index 2de52bad390..e3433a18d7a 100644 --- a/lib/l10n/ja.js +++ b/lib/l10n/ja.js @@ -113,8 +113,11 @@ OC.L10N.register( "Sharing %s failed, because resharing is not allowed" : "%s を共有できませんでした。再共有は許可されていません。", "Sharing %s failed, because the sharing backend for %s could not find its source" : "%s の共有に失敗しました。%s のバックエンド共有に必要なソースが見つかりませんでした。", "Sharing %s failed, because the file could not be found in the file cache" : "%s の共有に失敗しました。ファイルキャッシュにファイルがありませんでした。", + "Expiration date is in the past" : "有効期限が切れています", + "Cannot set expiration date more than %s days in the future" : "有効期限を%s日以降に設定できません。", "Could not find category \"%s\"" : "カテゴリ \"%s\" が見つかりませんでした", "Apps" : "アプリ", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"", "A valid username must be provided" : "有効なユーザー名を指定する必要があります", "A valid password must be provided" : "有効なパスワードを指定する必要があります", "The username is already being used" : "ユーザー名はすでに使われています", diff --git a/lib/l10n/ja.json b/lib/l10n/ja.json index 42b9b1912c7..a4b18386c7a 100644 --- a/lib/l10n/ja.json +++ b/lib/l10n/ja.json @@ -111,8 +111,11 @@ "Sharing %s failed, because resharing is not allowed" : "%s を共有できませんでした。再共有は許可されていません。", "Sharing %s failed, because the sharing backend for %s could not find its source" : "%s の共有に失敗しました。%s のバックエンド共有に必要なソースが見つかりませんでした。", "Sharing %s failed, because the file could not be found in the file cache" : "%s の共有に失敗しました。ファイルキャッシュにファイルがありませんでした。", + "Expiration date is in the past" : "有効期限が切れています", + "Cannot set expiration date more than %s days in the future" : "有効期限を%s日以降に設定できません。", "Could not find category \"%s\"" : "カテゴリ \"%s\" が見つかりませんでした", "Apps" : "アプリ", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "ユーザー名で利用できる文字列は、次のものです: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-\"", "A valid username must be provided" : "有効なユーザー名を指定する必要があります", "A valid password must be provided" : "有効なパスワードを指定する必要があります", "The username is already being used" : "ユーザー名はすでに使われています", diff --git a/lib/l10n/nl.js b/lib/l10n/nl.js index b2427d3f1ee..e49ddc6d27c 100644 --- a/lib/l10n/nl.js +++ b/lib/l10n/nl.js @@ -118,6 +118,7 @@ OC.L10N.register( "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen", "Could not find category \"%s\"" : "Kon categorie \"%s\" niet vinden", "Apps" : "Apps", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", en \"_.@-\"", "A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven", "A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven", "The username is already being used" : "De gebruikersnaam bestaat al", diff --git a/lib/l10n/nl.json b/lib/l10n/nl.json index 094866dc08b..78b54fbbc6d 100644 --- a/lib/l10n/nl.json +++ b/lib/l10n/nl.json @@ -116,6 +116,7 @@ "Cannot set expiration date more than %s days in the future" : "Kan vervaldatum niet verder dan %s dagen in de toekomst instellen", "Could not find category \"%s\"" : "Kon categorie \"%s\" niet vinden", "Apps" : "Apps", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Alleen de volgende tekens zijn toegestaan in een gebruikersnaam: \"a-z\", \"A-Z\", \"0-9\", en \"_.@-\"", "A valid username must be provided" : "Er moet een geldige gebruikersnaam worden opgegeven", "A valid password must be provided" : "Er moet een geldig wachtwoord worden opgegeven", "The username is already being used" : "De gebruikersnaam bestaat al", diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js index a9a282882c6..1ffbdc17a7b 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -118,6 +118,7 @@ OC.L10N.register( "Cannot set expiration date more than %s days in the future" : "Não é possível definir a data de validade mais de %s dias no futuro", "Could not find category \"%s\"" : "Impossível localizar categoria \"%s\"", "Apps" : "Aplicações", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", "A valid username must be provided" : "Forneça um nome de usuário válido", "A valid password must be provided" : "Forneça uma senha válida", "The username is already being used" : "Este nome de usuário já está sendo usado", diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json index 0a2ed3628dd..cb0e48af0db 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -116,6 +116,7 @@ "Cannot set expiration date more than %s days in the future" : "Não é possível definir a data de validade mais de %s dias no futuro", "Could not find category \"%s\"" : "Impossível localizar categoria \"%s\"", "Apps" : "Aplicações", + "Only the following characters are allowed in a username: \"a-z\", \"A-Z\", \"0-9\", and \"_.@-'\"" : "Somente os seguintes caracteres são permitidos em um nome de usuário: \"a-z\", \"A-Z\", \"0-9\", e \"_.@-'\"", "A valid username must be provided" : "Forneça um nome de usuário válido", "A valid password must be provided" : "Forneça uma senha válida", "The username is already being used" : "Este nome de usuário já está sendo usado", diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php index 61a04482431..ff9da88cd81 100644 --- a/lib/private/appframework/dependencyinjection/dicontainer.php +++ b/lib/private/appframework/dependencyinjection/dicontainer.php @@ -32,7 +32,6 @@ namespace OC\AppFramework\DependencyInjection; use OC; use OC\AppFramework\Http; -use OC\AppFramework\Http\Request; use OC\AppFramework\Http\Dispatcher; use OC\AppFramework\Http\Output; use OC\AppFramework\Core\API; @@ -43,8 +42,6 @@ use OC\AppFramework\Middleware\SessionMiddleware; use OC\AppFramework\Utility\SimpleContainer; use OCP\AppFramework\IApi; use OCP\AppFramework\IAppContainer; -use OCP\AppFramework\Middleware; -use OCP\IServerContainer; class DIContainer extends SimpleContainer implements IAppContainer { @@ -255,6 +252,10 @@ class DIContainer extends SimpleContainer implements IAppContainer { return $this->getServer()->getSession(); }); + $this->registerService('OCP\\Security\\IContentSecurityPolicyManager', function($c) { + return $this->getServer()->getContentSecurityPolicyManager(); + }); + $this->registerService('ServerContainer', function ($c) { return $this->getServer(); }); @@ -319,7 +320,8 @@ class DIContainer extends SimpleContainer implements IAppContainer { $app->getServer()->getLogger(), $c['AppName'], $app->isLoggedIn(), - $app->isAdminUser() + $app->isAdminUser(), + $app->getServer()->getContentSecurityPolicyManager() ); }); diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php index 4ef043ad50f..f1ba98254f0 100644 --- a/lib/private/appframework/middleware/security/securitymiddleware.php +++ b/lib/private/appframework/middleware/security/securitymiddleware.php @@ -32,6 +32,8 @@ use OC\Appframework\Middleware\Security\Exceptions\CrossSiteRequestForgeryExcept use OC\Appframework\Middleware\Security\Exceptions\NotAdminException; use OC\Appframework\Middleware\Security\Exceptions\NotLoggedInException; use OC\AppFramework\Utility\ControllerMethodReflector; +use OC\Security\CSP\ContentSecurityPolicyManager; +use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Middleware; @@ -52,15 +54,24 @@ use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; * check fails */ class SecurityMiddleware extends Middleware { - + /** @var INavigationManager */ private $navigationManager; + /** @var IRequest */ private $request; + /** @var ControllerMethodReflector */ private $reflector; + /** @var string */ private $appName; + /** @var IURLGenerator */ private $urlGenerator; + /** @var ILogger */ private $logger; + /** @var bool */ private $isLoggedIn; + /** @var bool */ private $isAdminUser; + /** @var ContentSecurityPolicyManager */ + private $contentSecurityPolicyManager; /** * @param IRequest $request @@ -71,6 +82,7 @@ class SecurityMiddleware extends Middleware { * @param string $appName * @param bool $isLoggedIn * @param bool $isAdminUser + * @param ContentSecurityPolicyManager $contentSecurityPolicyManager */ public function __construct(IRequest $request, ControllerMethodReflector $reflector, @@ -79,7 +91,8 @@ class SecurityMiddleware extends Middleware { ILogger $logger, $appName, $isLoggedIn, - $isAdminUser) { + $isAdminUser, + ContentSecurityPolicyManager $contentSecurityPolicyManager) { $this->navigationManager = $navigationManager; $this->request = $request; $this->reflector = $reflector; @@ -88,6 +101,7 @@ class SecurityMiddleware extends Middleware { $this->logger = $logger; $this->isLoggedIn = $isLoggedIn; $this->isAdminUser = $isAdminUser; + $this->contentSecurityPolicyManager = $contentSecurityPolicyManager; } @@ -139,6 +153,25 @@ class SecurityMiddleware extends Middleware { } + /** + * Performs the default CSP modifications that may be injected by other + * applications + * + * @param Controller $controller + * @param string $methodName + * @param Response $response + * @return Response + */ + public function afterController($controller, $methodName, Response $response) { + $policy = !is_null($response->getContentSecurityPolicy()) ? $response->getContentSecurityPolicy() : new ContentSecurityPolicy(); + + $defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy(); + $defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy); + + $response->setContentSecurityPolicy($defaultPolicy); + + return $response; + } /** * If an SecurityException is being caught, ajax requests return a JSON error diff --git a/lib/private/security/csp/contentsecuritypolicy.php b/lib/private/security/csp/contentsecuritypolicy.php new file mode 100644 index 00000000000..25eacfab1d6 --- /dev/null +++ b/lib/private/security/csp/contentsecuritypolicy.php @@ -0,0 +1,199 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OC\Security\CSP; + +/** + * Class ContentSecurityPolicy extends the public class and adds getter and setters. + * This is necessary since we don't want to expose the setters and getters to the + * public API. + * + * @package OC\Security\CSP + */ +class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy { + /** + * @return boolean + */ + public function isInlineScriptAllowed() { + return $this->inlineScriptAllowed; + } + + /** + * @param boolean $inlineScriptAllowed + */ + public function setInlineScriptAllowed($inlineScriptAllowed) { + $this->inlineScriptAllowed = $inlineScriptAllowed; + } + + /** + * @return boolean + */ + public function isEvalScriptAllowed() { + return $this->evalScriptAllowed; + } + + /** + * @param boolean $evalScriptAllowed + */ + public function setEvalScriptAllowed($evalScriptAllowed) { + $this->evalScriptAllowed = $evalScriptAllowed; + } + + /** + * @return array + */ + public function getAllowedScriptDomains() { + return $this->allowedScriptDomains; + } + + /** + * @param array $allowedScriptDomains + */ + public function setAllowedScriptDomains($allowedScriptDomains) { + $this->allowedScriptDomains = $allowedScriptDomains; + } + + /** + * @return boolean + */ + public function isInlineStyleAllowed() { + return $this->inlineStyleAllowed; + } + + /** + * @param boolean $inlineStyleAllowed + */ + public function setInlineStyleAllowed($inlineStyleAllowed) { + $this->inlineStyleAllowed = $inlineStyleAllowed; + } + + /** + * @return array + */ + public function getAllowedStyleDomains() { + return $this->allowedStyleDomains; + } + + /** + * @param array $allowedStyleDomains + */ + public function setAllowedStyleDomains($allowedStyleDomains) { + $this->allowedStyleDomains = $allowedStyleDomains; + } + + /** + * @return array + */ + public function getAllowedImageDomains() { + return $this->allowedImageDomains; + } + + /** + * @param array $allowedImageDomains + */ + public function setAllowedImageDomains($allowedImageDomains) { + $this->allowedImageDomains = $allowedImageDomains; + } + + /** + * @return array + */ + public function getAllowedConnectDomains() { + return $this->allowedConnectDomains; + } + + /** + * @param array $allowedConnectDomains + */ + public function setAllowedConnectDomains($allowedConnectDomains) { + $this->allowedConnectDomains = $allowedConnectDomains; + } + + /** + * @return array + */ + public function getAllowedMediaDomains() { + return $this->allowedMediaDomains; + } + + /** + * @param array $allowedMediaDomains + */ + public function setAllowedMediaDomains($allowedMediaDomains) { + $this->allowedMediaDomains = $allowedMediaDomains; + } + + /** + * @return array + */ + public function getAllowedObjectDomains() { + return $this->allowedObjectDomains; + } + + /** + * @param array $allowedObjectDomains + */ + public function setAllowedObjectDomains($allowedObjectDomains) { + $this->allowedObjectDomains = $allowedObjectDomains; + } + + /** + * @return array + */ + public function getAllowedFrameDomains() { + return $this->allowedFrameDomains; + } + + /** + * @param array $allowedFrameDomains + */ + public function setAllowedFrameDomains($allowedFrameDomains) { + $this->allowedFrameDomains = $allowedFrameDomains; + } + + /** + * @return array + */ + public function getAllowedFontDomains() { + return $this->allowedFontDomains; + } + + /** + * @param array $allowedFontDomains + */ + public function setAllowedFontDomains($allowedFontDomains) { + $this->allowedFontDomains = $allowedFontDomains; + } + + /** + * @return array + */ + public function getAllowedChildSrcDomains() { + return $this->allowedChildSrcDomains; + } + + /** + * @param array $allowedChildSrcDomains + */ + public function setAllowedChildSrcDomains($allowedChildSrcDomains) { + $this->allowedChildSrcDomains = $allowedChildSrcDomains; + } + +} diff --git a/lib/private/security/csp/contentsecuritypolicymanager.php b/lib/private/security/csp/contentsecuritypolicymanager.php new file mode 100644 index 00000000000..760cd36e56b --- /dev/null +++ b/lib/private/security/csp/contentsecuritypolicymanager.php @@ -0,0 +1,73 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Security\CSP; + +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\EmptyContentSecurityPolicy; +use OCP\Security\IContentSecurityPolicyManager; + +class ContentSecurityPolicyManager implements IContentSecurityPolicyManager { + /** @var ContentSecurityPolicy[] */ + private $policies = []; + + /** {@inheritdoc} */ + public function addDefaultPolicy(EmptyContentSecurityPolicy $policy) { + $this->policies[] = $policy; + } + + /** + * Get the configured default policy. This is not in the public namespace + * as it is only supposed to be used by core itself. + * + * @return ContentSecurityPolicy + */ + public function getDefaultPolicy() { + $defaultPolicy = new \OC\Security\CSP\ContentSecurityPolicy(); + foreach($this->policies as $policy) { + $defaultPolicy = $this->mergePolicies($defaultPolicy, $policy); + } + return $defaultPolicy; + } + + /** + * Merges the first given policy with the second one + * + * @param ContentSecurityPolicy $defaultPolicy + * @param EmptyContentSecurityPolicy $originalPolicy + * @return ContentSecurityPolicy + */ + public function mergePolicies(ContentSecurityPolicy $defaultPolicy, + EmptyContentSecurityPolicy $originalPolicy) { + foreach((object)(array)$originalPolicy as $name => $value) { + $setter = 'set'.ucfirst($name); + if(is_array($value)) { + $getter = 'get'.ucfirst($name); + $currentValues = is_array($defaultPolicy->$getter()) ? $defaultPolicy->$getter() : []; + $defaultPolicy->$setter(array_values(array_unique(array_merge($currentValues, $value)))); + } elseif (is_bool($value)) { + $defaultPolicy->$setter($value); + } + } + + return $defaultPolicy; + } +} diff --git a/lib/private/server.php b/lib/private/server.php index d453a42d3a0..d3dbcba86ba 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -63,6 +63,7 @@ use OC\Lock\NoopLockingProvider; use OC\Mail\Mailer; use OC\Notification\Manager; use OC\Security\CertificateManager; +use OC\Security\CSP\ContentSecurityPolicyManager; use OC\Security\Crypto; use OC\Security\CSRF\CsrfTokenGenerator; use OC\Security\CSRF\CsrfTokenManager; @@ -74,6 +75,7 @@ use OC\Security\TrustedDomainHelper; use OC\Session\CryptoWrapper; use OC\Tagging\TagMapper; use OCP\IServerContainer; +use OCP\Security\IContentSecurityPolicyManager; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -598,6 +600,9 @@ class Server extends ServerContainer implements IServerContainer { $sessionStorage ); }); + $this->registerService('ContentSecurityPolicyManager', function (Server $c) { + return new ContentSecurityPolicyManager(); + }); $this->registerService('ShareManager', function(Server $c) { $config = $c->getConfig(); $factoryClass = $config->getSystemValue('sharing.managerFactory', '\OC\Share20\ProviderFactory'); @@ -1221,6 +1226,13 @@ class Server extends ServerContainer implements IServerContainer { } /** + * @return IContentSecurityPolicyManager + */ + public function getContentSecurityPolicyManager() { + return $this->query('ContentSecurityPolicyManager'); + } + + /** * Not a public API as of 8.2, wait for 9.0 * * @return \OCA\Files_External\Service\BackendService diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php index 35b3f71f3de..0fa1552a1e7 100644 --- a/lib/private/share20/defaultshareprovider.php +++ b/lib/private/share20/defaultshareprovider.php @@ -518,16 +518,9 @@ class DefaultShareProvider implements IShareProvider { } /** - * Get shared with the given user - * - * @param IUser $user get shares where this user is the recipient - * @param int $shareType \OCP\Share::SHARE_TYPE_USER or \OCP\Share::SHARE_TYPE_GROUP are supported - * @param int $limit The maximum number of shares, -1 for all - * @param int $offset - * @return IShare[] - * @throws BackendError + * @inheritdoc */ - public function getSharedWith(IUser $user, $shareType, $limit, $offset) { + public function getSharedWith(IUser $user, $shareType, $node, $limit, $offset) { /** @var Share[] $shares */ $shares = []; @@ -549,6 +542,11 @@ class DefaultShareProvider implements IShareProvider { $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER))); $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($user->getUID()))); + // Filter by node if provided + if ($node !== null) { + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); + } + $cursor = $qb->execute(); while($data = $cursor->fetch()) { @@ -581,9 +579,14 @@ class DefaultShareProvider implements IShareProvider { $qb->setMaxResults($limit - count($shares)); } + // Filter by node if provided + if ($node !== null) { + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); + } + $groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups); - $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))); + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))); $qb->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter( $groups, IQueryBuilder::PARAM_STR_ARRAY diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php index d6245f4beac..ad5fed93904 100644 --- a/lib/private/share20/manager.php +++ b/lib/private/share20/manager.php @@ -21,6 +21,7 @@ namespace OC\Share20; +use OCP\Files\Node; use OCP\Share\IManager; use OCP\Share\IProviderFactory; use OC\Share20\Exception\BackendError; @@ -722,18 +723,12 @@ class Manager implements IManager { } /** - * Get shares shared with $user. - * - * @param IUser $user - * @param int $shareType - * @param int $limit The maximum number of shares returned, -1 for all - * @param int $offset - * @return \OCP\Share\IShare[] + * @inheritdoc */ - public function getSharedWith(IUser $user, $shareType, $limit = 50, $offset = 0) { + public function getSharedWith(IUser $user, $shareType, $node = null, $limit = 50, $offset = 0) { $provider = $this->factory->getProviderForType($shareType); - return $provider->getSharedWith($user, $shareType, $limit, $offset); + return $provider->getSharedWith($user, $shareType, $node, $limit, $offset); } /** diff --git a/lib/public/appframework/controller.php b/lib/public/appframework/controller.php index 973c9044684..c3744683300 100644 --- a/lib/public/appframework/controller.php +++ b/lib/public/appframework/controller.php @@ -72,7 +72,7 @@ abstract class Controller { * @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0 */ public function __construct($appName, - IRequest $request){ + IRequest $request) { $this->appName = $appName; $this->request = $request; diff --git a/lib/public/appframework/http/contentsecuritypolicy.php b/lib/public/appframework/http/contentsecuritypolicy.php index 35da4f05e80..7762ca809a2 100644 --- a/lib/public/appframework/http/contentsecuritypolicy.php +++ b/lib/public/appframework/http/contentsecuritypolicy.php @@ -38,17 +38,17 @@ use OCP\AppFramework\Http; * @package OCP\AppFramework\Http * @since 8.1.0 */ -class ContentSecurityPolicy { +class ContentSecurityPolicy extends EmptyContentSecurityPolicy { /** @var bool Whether inline JS snippets are allowed */ - private $inlineScriptAllowed = false; + protected $inlineScriptAllowed = false; /** * @var bool Whether eval in JS scripts is allowed * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/11925 */ - private $evalScriptAllowed = true; + protected $evalScriptAllowed = true; /** @var array Domains from which scripts can get loaded */ - private $allowedScriptDomains = [ + protected $allowedScriptDomains = [ '\'self\'', ]; /** @@ -56,342 +56,33 @@ class ContentSecurityPolicy { * TODO: Disallow per default * @link https://github.com/owncloud/core/issues/13458 */ - private $inlineStyleAllowed = true; + protected $inlineStyleAllowed = true; /** @var array Domains from which CSS can get loaded */ - private $allowedStyleDomains = [ + protected $allowedStyleDomains = [ '\'self\'', ]; /** @var array Domains from which images can get loaded */ - private $allowedImageDomains = [ + protected $allowedImageDomains = [ '\'self\'', 'data:', 'blob:', ]; /** @var array Domains to which connections can be done */ - private $allowedConnectDomains = [ + protected $allowedConnectDomains = [ '\'self\'', ]; /** @var array Domains from which media elements can be loaded */ - private $allowedMediaDomains = [ + protected $allowedMediaDomains = [ '\'self\'', ]; /** @var array Domains from which object elements can be loaded */ - private $allowedObjectDomains = []; + protected $allowedObjectDomains = []; /** @var array Domains from which iframes can be loaded */ - private $allowedFrameDomains = []; + protected $allowedFrameDomains = []; /** @var array Domains from which fonts can be loaded */ - private $allowedFontDomains = [ + protected $allowedFontDomains = [ '\'self\'', ]; /** @var array Domains from which web-workers and nested browsing content can load elements */ - private $allowedChildSrcDomains = []; - - /** - * Whether inline JavaScript snippets are allowed or forbidden - * @param bool $state - * @return $this - * @since 8.1.0 - */ - public function allowInlineScript($state = false) { - $this->inlineScriptAllowed = $state; - return $this; - } - - /** - * Whether eval in JavaScript is allowed or forbidden - * @param bool $state - * @return $this - * @since 8.1.0 - */ - public function allowEvalScript($state = true) { - $this->evalScriptAllowed = $state; - return $this; - } - - /** - * Allows to execute JavaScript files from a specific domain. Use * to - * allow JavaScript from all domains. - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedScriptDomain($domain) { - $this->allowedScriptDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed script domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowScriptDomain($domain) { - $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]); - return $this; - } - - /** - * Whether inline CSS snippets are allowed or forbidden - * @param bool $state - * @return $this - * @since 8.1.0 - */ - public function allowInlineStyle($state = true) { - $this->inlineStyleAllowed = $state; - return $this; - } - - /** - * Allows to execute CSS files from a specific domain. Use * to allow - * CSS from all domains. - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedStyleDomain($domain) { - $this->allowedStyleDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed style domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowStyleDomain($domain) { - $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]); - return $this; - } - - /** - * Allows using fonts from a specific domain. Use * to allow - * fonts from all domains. - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedFontDomain($domain) { - $this->allowedFontDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed font domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowFontDomain($domain) { - $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]); - return $this; - } - - /** - * Allows embedding images from a specific domain. Use * to allow - * images from all domains. - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedImageDomain($domain) { - $this->allowedImageDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed image domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowImageDomain($domain) { - $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]); - return $this; - } - - /** - * To which remote domains the JS connect to. - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedConnectDomain($domain) { - $this->allowedConnectDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed connect domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowConnectDomain($domain) { - $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]); - return $this; - } - - /** - * From which domains media elements can be embedded. - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedMediaDomain($domain) { - $this->allowedMediaDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed media domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowMediaDomain($domain) { - $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]); - return $this; - } - - /** - * From which domains objects such as <object>, <embed> or <applet> are executed - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedObjectDomain($domain) { - $this->allowedObjectDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed object domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowObjectDomain($domain) { - $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]); - return $this; - } - - /** - * Which domains can be embedded in an iframe - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedFrameDomain($domain) { - $this->allowedFrameDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed frame domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowFrameDomain($domain) { - $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]); - return $this; - } - - /** - * Domains from which web-workers and nested browsing content can load elements - * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. - * @return $this - * @since 8.1.0 - */ - public function addAllowedChildSrcDomain($domain) { - $this->allowedChildSrcDomains[] = $domain; - return $this; - } - - /** - * Remove the specified allowed child src domain from the allowed domains. - * - * @param string $domain - * @return $this - * @since 8.1.0 - */ - public function disallowChildSrcDomain($domain) { - $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]); - return $this; - } - - /** - * Get the generated Content-Security-Policy as a string - * @return string - * @since 8.1.0 - */ - public function buildPolicy() { - $policy = "default-src 'none';"; - - if(!empty($this->allowedScriptDomains)) { - $policy .= 'script-src ' . implode(' ', $this->allowedScriptDomains); - if($this->inlineScriptAllowed) { - $policy .= ' \'unsafe-inline\''; - } - if($this->evalScriptAllowed) { - $policy .= ' \'unsafe-eval\''; - } - $policy .= ';'; - } - - if(!empty($this->allowedStyleDomains)) { - $policy .= 'style-src ' . implode(' ', $this->allowedStyleDomains); - if($this->inlineStyleAllowed) { - $policy .= ' \'unsafe-inline\''; - } - $policy .= ';'; - } - - if(!empty($this->allowedImageDomains)) { - $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains); - $policy .= ';'; - } - - if(!empty($this->allowedFontDomains)) { - $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains); - $policy .= ';'; - } - - if(!empty($this->allowedConnectDomains)) { - $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains); - $policy .= ';'; - } - - if(!empty($this->allowedMediaDomains)) { - $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains); - $policy .= ';'; - } - - if(!empty($this->allowedObjectDomains)) { - $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains); - $policy .= ';'; - } - - if(!empty($this->allowedFrameDomains)) { - $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains); - $policy .= ';'; - } - - if(!empty($this->allowedChildSrcDomains)) { - $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains); - $policy .= ';'; - } - - return rtrim($policy, ';'); - } + protected $allowedChildSrcDomains = []; } diff --git a/lib/public/appframework/http/emptycontentsecuritypolicy.php b/lib/public/appframework/http/emptycontentsecuritypolicy.php new file mode 100644 index 00000000000..33860dcdb0f --- /dev/null +++ b/lib/public/appframework/http/emptycontentsecuritypolicy.php @@ -0,0 +1,387 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author sualko <klaus@jsxc.org> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * Class EmptyContentSecurityPolicy is a simple helper which allows applications + * to modify the Content-Security-Policy sent by ownCloud. Per default the policy + * is forbidding everything. + * + * As alternative with sane exemptions look at ContentSecurityPolicy + * + * @see \OCP\AppFramework\Http\ContentSecurityPolicy + * @package OCP\AppFramework\Http + * @since 9.0.0 + */ +class EmptyContentSecurityPolicy { + /** @var bool Whether inline JS snippets are allowed */ + protected $inlineScriptAllowed = null; + /** + * @var bool Whether eval in JS scripts is allowed + * TODO: Disallow per default + * @link https://github.com/owncloud/core/issues/11925 + */ + protected $evalScriptAllowed = null; + /** @var array Domains from which scripts can get loaded */ + protected $allowedScriptDomains = null; + /** + * @var bool Whether inline CSS is allowed + * TODO: Disallow per default + * @link https://github.com/owncloud/core/issues/13458 + */ + protected $inlineStyleAllowed = null; + /** @var array Domains from which CSS can get loaded */ + protected $allowedStyleDomains = null; + /** @var array Domains from which images can get loaded */ + protected $allowedImageDomains = null; + /** @var array Domains to which connections can be done */ + protected $allowedConnectDomains = null; + /** @var array Domains from which media elements can be loaded */ + protected $allowedMediaDomains = null; + /** @var array Domains from which object elements can be loaded */ + protected $allowedObjectDomains = null; + /** @var array Domains from which iframes can be loaded */ + protected $allowedFrameDomains = null; + /** @var array Domains from which fonts can be loaded */ + protected $allowedFontDomains = null; + /** @var array Domains from which web-workers and nested browsing content can load elements */ + protected $allowedChildSrcDomains = null; + + /** + * Whether inline JavaScript snippets are allowed or forbidden + * @param bool $state + * @return $this + * @since 8.1.0 + */ + public function allowInlineScript($state = false) { + $this->inlineScriptAllowed = $state; + return $this; + } + + /** + * Whether eval in JavaScript is allowed or forbidden + * @param bool $state + * @return $this + * @since 8.1.0 + */ + public function allowEvalScript($state = true) { + $this->evalScriptAllowed = $state; + return $this; + } + + /** + * Allows to execute JavaScript files from a specific domain. Use * to + * allow JavaScript from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedScriptDomain($domain) { + $this->allowedScriptDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed script domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowScriptDomain($domain) { + $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]); + return $this; + } + + /** + * Whether inline CSS snippets are allowed or forbidden + * @param bool $state + * @return $this + * @since 8.1.0 + */ + public function allowInlineStyle($state = true) { + $this->inlineStyleAllowed = $state; + return $this; + } + + /** + * Allows to execute CSS files from a specific domain. Use * to allow + * CSS from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedStyleDomain($domain) { + $this->allowedStyleDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed style domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowStyleDomain($domain) { + $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]); + return $this; + } + + /** + * Allows using fonts from a specific domain. Use * to allow + * fonts from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedFontDomain($domain) { + $this->allowedFontDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed font domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowFontDomain($domain) { + $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]); + return $this; + } + + /** + * Allows embedding images from a specific domain. Use * to allow + * images from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedImageDomain($domain) { + $this->allowedImageDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed image domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowImageDomain($domain) { + $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]); + return $this; + } + + /** + * To which remote domains the JS connect to. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedConnectDomain($domain) { + $this->allowedConnectDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed connect domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowConnectDomain($domain) { + $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]); + return $this; + } + + /** + * From which domains media elements can be embedded. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedMediaDomain($domain) { + $this->allowedMediaDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed media domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowMediaDomain($domain) { + $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]); + return $this; + } + + /** + * From which domains objects such as <object>, <embed> or <applet> are executed + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedObjectDomain($domain) { + $this->allowedObjectDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed object domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowObjectDomain($domain) { + $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]); + return $this; + } + + /** + * Which domains can be embedded in an iframe + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedFrameDomain($domain) { + $this->allowedFrameDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed frame domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowFrameDomain($domain) { + $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]); + return $this; + } + + /** + * Domains from which web-workers and nested browsing content can load elements + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedChildSrcDomain($domain) { + $this->allowedChildSrcDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed child src domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowChildSrcDomain($domain) { + $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]); + return $this; + } + + /** + * Get the generated Content-Security-Policy as a string + * @return string + * @since 8.1.0 + */ + public function buildPolicy() { + $policy = "default-src 'none';"; + + if(!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) { + $policy .= 'script-src '; + if(is_array($this->allowedScriptDomains)) { + $policy .= implode(' ', $this->allowedScriptDomains); + } + if($this->inlineScriptAllowed) { + $policy .= ' \'unsafe-inline\''; + } + if($this->evalScriptAllowed) { + $policy .= ' \'unsafe-eval\''; + } + $policy .= ';'; + } + + if(!empty($this->allowedStyleDomains) || $this->inlineStyleAllowed) { + $policy .= 'style-src '; + if(is_array($this->allowedStyleDomains)) { + $policy .= implode(' ', $this->allowedStyleDomains); + } + if($this->inlineStyleAllowed) { + $policy .= ' \'unsafe-inline\''; + } + $policy .= ';'; + } + + if(!empty($this->allowedImageDomains)) { + $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains); + $policy .= ';'; + } + + if(!empty($this->allowedFontDomains)) { + $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains); + $policy .= ';'; + } + + if(!empty($this->allowedConnectDomains)) { + $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains); + $policy .= ';'; + } + + if(!empty($this->allowedMediaDomains)) { + $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains); + $policy .= ';'; + } + + if(!empty($this->allowedObjectDomains)) { + $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains); + $policy .= ';'; + } + + if(!empty($this->allowedFrameDomains)) { + $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains); + $policy .= ';'; + } + + if(!empty($this->allowedChildSrcDomains)) { + $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains); + $policy .= ';'; + } + + return rtrim($policy, ';'); + } +} diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php index 4572a69f047..f9ac79d66ec 100644 --- a/lib/public/files/storagenotavailableexception.php +++ b/lib/public/files/storagenotavailableexception.php @@ -54,7 +54,7 @@ class StorageNotAvailableException extends HintException { * @param \Exception $previous * @since 6.0.0 */ - public function __construct($message = '', $code = 0, \Exception $previous = null) { + public function __construct($message = '', $code = self::STATUS_ERROR, \Exception $previous = null) { $l = \OC::$server->getL10N('core'); parent::__construct($message, $l->t('Storage not available'), $code, $previous); } diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index ce1364cc4ea..de48daeef88 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -42,6 +42,7 @@ // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP; +use OCP\Security\IContentSecurityPolicyManager; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -512,4 +513,10 @@ interface IServerContainer { * @since 9.0.0 */ public function getShareManager(); + + /** + * @return IContentSecurityPolicyManager + * @since 9.0.0 + */ + public function getContentSecurityPolicyManager(); } diff --git a/lib/public/security/icontentsecuritypolicymanager.php b/lib/public/security/icontentsecuritypolicymanager.php new file mode 100644 index 00000000000..10f1efe995f --- /dev/null +++ b/lib/public/security/icontentsecuritypolicymanager.php @@ -0,0 +1,50 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\Security; +use OCP\AppFramework\Http\EmptyContentSecurityPolicy; + +/** + * Used for Content Security Policy manipulations + * + * @package OCP\Security + * @since 9.0.0 + */ +interface IContentSecurityPolicyManager { + /** + * Allows to inject something into the default content policy. This is for + * example useful when you're injecting Javascript code into a view belonging + * to another controller and cannot modify its Content-Security-Policy itself. + * Note that the adjustment is only applied to applications that use AppFramework + * controllers. + * + * To use this from your `app.php` use `\OC::$server->getContentSecurityPolicyManager()->addDefaultPolicy($policy)`, + * $policy has to be of type `\OCP\AppFramework\Http\ContentSecurityPolicy`. + * + * WARNING: Using this API incorrectly may make the instance more insecure. + * Do think twice before adding whitelisting resources. Please do also note + * that it is not possible to use the `disallowXYZ` functions. + * + * @param EmptyContentSecurityPolicy $policy + * @since 9.0.0 + */ + public function addDefaultPolicy(EmptyContentSecurityPolicy $policy); +} diff --git a/lib/public/share/imanager.php b/lib/public/share/imanager.php index 6531c14a857..b2d9953e9ef 100644 --- a/lib/public/share/imanager.php +++ b/lib/public/share/imanager.php @@ -88,15 +88,17 @@ interface IManager { /** * Get shares shared with $user. + * Filter by $node if provided * * @param IUser $user * @param int $shareType + * @param File|Folder|null $node * @param int $limit The maximum number of shares returned, -1 for all * @param int $offset * @return IShare[] * @since 9.0.0 */ - public function getSharedWith(IUser $user, $shareType, $limit = 50, $offset = 0); + public function getSharedWith(IUser $user, $shareType, $node = null, $limit = 50, $offset = 0); /** * Retrieve a share by the share id diff --git a/lib/public/share/ishareprovider.php b/lib/public/share/ishareprovider.php index 50964c88dd6..8507462cbed 100644 --- a/lib/public/share/ishareprovider.php +++ b/lib/public/share/ishareprovider.php @@ -23,6 +23,7 @@ namespace OCP\Share; use OC\Share20\Exception\ShareNotFound; use OC\Share20\Exception\BackendError; +use OCP\Files\Node; use OCP\IUser; /** @@ -116,12 +117,13 @@ interface IShareProvider { * * @param IUser $user get shares where this user is the recipient * @param int $shareType + * @param Node|null $node * @param int $limit The max number of entries returned, -1 for all * @param int $offset * @return \OCP\Share\IShare[] * @since 9.0.0 */ - public function getSharedWith(IUser $user, $shareType, $limit, $offset); + public function getSharedWith(IUser $user, $shareType, $node, $limit, $offset); /** * Get a share by token diff --git a/settings/l10n/ja.js b/settings/l10n/ja.js index 65881d30d34..2d092c302d1 100644 --- a/settings/l10n/ja.js +++ b/settings/l10n/ja.js @@ -209,6 +209,8 @@ OC.L10N.register( "Admin documentation" : "管理者ドキュメント", "Show description …" : "説明を表示 ...", "Hide description …" : "説明を隠す ...", + "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最小バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.", + "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最大バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.", "This app cannot be installed because the following dependencies are not fulfilled:" : "次の依存関係が満たされないためこのアプリをインストールできません:", "Enable only for specific groups" : "特定のグループのみ有効に", "Uninstall App" : "アプリをアンインストール", diff --git a/settings/l10n/ja.json b/settings/l10n/ja.json index 05d43d0cd62..996a53df9c5 100644 --- a/settings/l10n/ja.json +++ b/settings/l10n/ja.json @@ -207,6 +207,8 @@ "Admin documentation" : "管理者ドキュメント", "Show description …" : "説明を表示 ...", "Hide description …" : "説明を隠す ...", + "This app has no minimum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最小バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.", + "This app has no maximum ownCloud version assigned. This will be an error in ownCloud 11 and later." : "このアプリはownCloudの最大バージョンが指定されていません.ownCloud 11 以降でエラーが発生する可能性があります.", "This app cannot be installed because the following dependencies are not fulfilled:" : "次の依存関係が満たされないためこのアプリをインストールできません:", "Enable only for specific groups" : "特定のグループのみ有効に", "Uninstall App" : "アプリをアンインストール", diff --git a/settings/l10n/nl.js b/settings/l10n/nl.js index 2aead6ae80f..60962c89c61 100644 --- a/settings/l10n/nl.js +++ b/settings/l10n/nl.js @@ -204,6 +204,8 @@ OC.L10N.register( "Developer documentation" : "Ontwikkelaarsdocumentatie", "Experimental applications ahead" : "Experimentele applicaties vooraan", "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentele apps zijn niet gecontroleerd op beveiligingsproblemen, zijn nieuw of staan bekend als instabiel en worden volop ontwikkeld. Installatie kan leiden tot gegevensverlies of beveiligingsincidenten.", + "by %s" : "op %s", + "%s-licensed" : "%s-licensed", "Documentation:" : "Documentatie:", "User documentation" : "Gebruikersdocumentatie", "Admin documentation" : "Beheerdocumentatie", diff --git a/settings/l10n/nl.json b/settings/l10n/nl.json index b72ac4f860c..2c201e83e30 100644 --- a/settings/l10n/nl.json +++ b/settings/l10n/nl.json @@ -202,6 +202,8 @@ "Developer documentation" : "Ontwikkelaarsdocumentatie", "Experimental applications ahead" : "Experimentele applicaties vooraan", "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Experimentele apps zijn niet gecontroleerd op beveiligingsproblemen, zijn nieuw of staan bekend als instabiel en worden volop ontwikkeld. Installatie kan leiden tot gegevensverlies of beveiligingsincidenten.", + "by %s" : "op %s", + "%s-licensed" : "%s-licensed", "Documentation:" : "Documentatie:", "User documentation" : "Gebruikersdocumentatie", "Admin documentation" : "Beheerdocumentatie", diff --git a/settings/l10n/pt_BR.js b/settings/l10n/pt_BR.js index 7d04bc3c04b..144c4a812f2 100644 --- a/settings/l10n/pt_BR.js +++ b/settings/l10n/pt_BR.js @@ -204,6 +204,8 @@ OC.L10N.register( "Developer documentation" : "Documentação do desenvolvedor", "Experimental applications ahead" : "Aplicações experimentais à frente", "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplicativos experimentais não são marcados por questões de segurança, por serem novos ou conhecidos como instáveis e sob forte desenvolvimento. Instalá-los pode causar perda de dados ou falhas de segurança.", + "by %s" : "por %s", + "%s-licensed" : "%s-licenciado", "Documentation:" : "Documentação:", "User documentation" : "Documentação do usuário", "Admin documentation" : "Documentação para Administração", diff --git a/settings/l10n/pt_BR.json b/settings/l10n/pt_BR.json index 100b7e60f22..fb06b056b44 100644 --- a/settings/l10n/pt_BR.json +++ b/settings/l10n/pt_BR.json @@ -202,6 +202,8 @@ "Developer documentation" : "Documentação do desenvolvedor", "Experimental applications ahead" : "Aplicações experimentais à frente", "Experimental apps are not checked for security issues, new or known to be unstable and under heavy development. Installing them can cause data loss or security breaches." : "Aplicativos experimentais não são marcados por questões de segurança, por serem novos ou conhecidos como instáveis e sob forte desenvolvimento. Instalá-los pode causar perda de dados ou falhas de segurança.", + "by %s" : "por %s", + "%s-licensed" : "%s-licenciado", "Documentation:" : "Documentação:", "User documentation" : "Documentação do usuário", "Admin documentation" : "Documentação para Administração", diff --git a/settings/l10n/zh_TW.js b/settings/l10n/zh_TW.js index 755befc2d5f..14e94ae0f30 100644 --- a/settings/l10n/zh_TW.js +++ b/settings/l10n/zh_TW.js @@ -277,7 +277,7 @@ OC.L10N.register( "Unlimited" : "無限制", "Other" : "其他", "Full Name" : "全名", - "Group Admin for" : "是以下群組的管理員", + "Group Admin for" : "指定群組管理者", "Quota" : "容量限制", "Storage Location" : "儲存位置", "User Backend" : "用戶後端", diff --git a/settings/l10n/zh_TW.json b/settings/l10n/zh_TW.json index e89a00e338f..0fc46a9ee8f 100644 --- a/settings/l10n/zh_TW.json +++ b/settings/l10n/zh_TW.json @@ -275,7 +275,7 @@ "Unlimited" : "無限制", "Other" : "其他", "Full Name" : "全名", - "Group Admin for" : "是以下群組的管理員", + "Group Admin for" : "指定群組管理者", "Quota" : "容量限制", "Storage Location" : "儲存位置", "User Backend" : "用戶後端", diff --git a/tests/lib/appframework/http/ContentSecurityPolicyTest.php b/tests/lib/appframework/http/ContentSecurityPolicyTest.php index 6d9c6d7b8d9..adf03185e9f 100644 --- a/tests/lib/appframework/http/ContentSecurityPolicyTest.php +++ b/tests/lib/appframework/http/ContentSecurityPolicyTest.php @@ -426,21 +426,4 @@ class ContentSecurityPolicyTest extends \Test\TestCase { $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - - public function testConfigureStacked() { - $expectedPolicy = "default-src 'none';script-src 'self' script.owncloud.org;style-src 'self' style.owncloud.org;img-src 'self' data: blob: img.owncloud.org;font-src 'self' font.owncloud.org;connect-src 'self' connect.owncloud.org;media-src 'self' media.owncloud.org;object-src objects.owncloud.org;frame-src frame.owncloud.org;child-src child.owncloud.org"; - - $this->contentSecurityPolicy->allowInlineStyle(false) - ->allowEvalScript(false) - ->addAllowedScriptDomain('script.owncloud.org') - ->addAllowedStyleDomain('style.owncloud.org') - ->addAllowedFontDomain('font.owncloud.org') - ->addAllowedImageDomain('img.owncloud.org') - ->addAllowedConnectDomain('connect.owncloud.org') - ->addAllowedMediaDomain('media.owncloud.org') - ->addAllowedObjectDomain('objects.owncloud.org') - ->addAllowedChildSrcDomain('child.owncloud.org') - ->addAllowedFrameDomain('frame.owncloud.org'); - $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); - } } diff --git a/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php b/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php new file mode 100644 index 00000000000..0d0f92de819 --- /dev/null +++ b/tests/lib/appframework/http/EmptyContentSecurityPolicyTest.php @@ -0,0 +1,430 @@ +<?php +/** + * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +namespace OC\AppFramework\Http; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\EmptyContentSecurityPolicy; + +/** + * Class ContentSecurityPolicyTest + * + * @package OC\AppFramework\Http + */ +class EmptyContentSecurityPolicyTest extends \Test\TestCase { + + /** @var EmptyContentSecurityPolicy */ + private $contentSecurityPolicy; + + public function setUp() { + parent::setUp(); + $this->contentSecurityPolicy = new EmptyContentSecurityPolicy(); + } + + public function testGetPolicyDefault() { + $defaultPolicy = "default-src 'none'"; + $this->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyScriptDomainValid() { + $expectedPolicy = "default-src 'none';script-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyScriptDomainValidMultiple() { + $expectedPolicy = "default-src 'none';script-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowScriptDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowScriptDomainMultiple() { + $expectedPolicy = "default-src 'none';script-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowScriptDomainMultipleStacked() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org')->disallowScriptDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyScriptAllowInline() { + $expectedPolicy = "default-src 'none';script-src 'unsafe-inline'"; + + $this->contentSecurityPolicy->allowInlineScript(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyScriptAllowInlineWithDomain() { + $expectedPolicy = "default-src 'none';script-src www.owncloud.com 'unsafe-inline'"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->allowInlineScript(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyScriptAllowInlineAndEval() { + $expectedPolicy = "default-src 'none';script-src 'unsafe-inline' 'unsafe-eval'"; + + $this->contentSecurityPolicy->allowInlineScript(true); + $this->contentSecurityPolicy->allowEvalScript(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStyleDomainValid() { + $expectedPolicy = "default-src 'none';style-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStyleDomainValidMultiple() { + $expectedPolicy = "default-src 'none';style-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowStyleDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowStyleDomainMultiple() { + $expectedPolicy = "default-src 'none';style-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowStyleDomainMultipleStacked() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org')->disallowStyleDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStyleAllowInline() { + $expectedPolicy = "default-src 'none';style-src 'unsafe-inline'"; + + $this->contentSecurityPolicy->allowInlineStyle(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStyleAllowInlineWithDomain() { + $expectedPolicy = "default-src 'none';style-src www.owncloud.com 'unsafe-inline'"; + + $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->allowInlineStyle(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStyleDisallowInline() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->allowInlineStyle(false); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyImageDomainValid() { + $expectedPolicy = "default-src 'none';img-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyImageDomainValidMultiple() { + $expectedPolicy = "default-src 'none';img-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowImageDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowImageDomainMultiple() { + $expectedPolicy = "default-src 'none';img-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowImageDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org')->disallowImageDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyFontDomainValid() { + $expectedPolicy = "default-src 'none';font-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyFontDomainValidMultiple() { + $expectedPolicy = "default-src 'none';font-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowFontDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowFontDomainMultiple() { + $expectedPolicy = "default-src 'none';font-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowFontDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org')->disallowFontDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyConnectDomainValid() { + $expectedPolicy = "default-src 'none';connect-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyConnectDomainValidMultiple() { + $expectedPolicy = "default-src 'none';connect-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowConnectDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowConnectDomainMultiple() { + $expectedPolicy = "default-src 'none';connect-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowConnectDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org')->disallowConnectDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyMediaDomainValid() { + $expectedPolicy = "default-src 'none';media-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyMediaDomainValidMultiple() { + $expectedPolicy = "default-src 'none';media-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowMediaDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowMediaDomainMultiple() { + $expectedPolicy = "default-src 'none';media-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowMediaDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org')->disallowMediaDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyObjectDomainValid() { + $expectedPolicy = "default-src 'none';object-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyObjectDomainValidMultiple() { + $expectedPolicy = "default-src 'none';object-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowObjectDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowObjectDomainMultiple() { + $expectedPolicy = "default-src 'none';object-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowObjectDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org')->disallowObjectDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetAllowedFrameDomain() { + $expectedPolicy = "default-src 'none';frame-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyFrameDomainValidMultiple() { + $expectedPolicy = "default-src 'none';frame-src www.owncloud.com www.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowFrameDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowFrameDomainMultiple() { + $expectedPolicy = "default-src 'none';frame-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowFrameDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org')->disallowFrameDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetAllowedChildSrcDomain() { + $expectedPolicy = "default-src 'none';child-src child.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyChildSrcValidMultiple() { + $expectedPolicy = "default-src 'none';child-src child.owncloud.com child.owncloud.org"; + + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowChildSrcDomain() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowChildSrcDomainMultiple() { + $expectedPolicy = "default-src 'none';child-src www.owncloud.com"; + + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyDisallowChildSrcDomainMultipleStakes() { + $expectedPolicy = "default-src 'none'"; + + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com'); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } +} diff --git a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php index 62223bbc2d9..9e71a3d0961 100644 --- a/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php +++ b/tests/lib/appframework/middleware/security/SecurityMiddlewareTest.php @@ -32,6 +32,7 @@ use OC\Appframework\Middleware\Security\Exceptions\NotAdminException; use OC\Appframework\Middleware\Security\Exceptions\NotLoggedInException; use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; use OC\AppFramework\Utility\ControllerMethodReflector; +use OC\Security\CSP\ContentSecurityPolicy; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; @@ -48,6 +49,7 @@ class SecurityMiddlewareTest extends \Test\TestCase { private $logger; private $navigationManager; private $urlGenerator; + private $contentSecurityPolicyManager; protected function setUp() { parent::setUp(); @@ -72,6 +74,10 @@ class SecurityMiddlewareTest extends \Test\TestCase { 'OCP\IRequest') ->disableOriginalConstructor() ->getMock(); + $this->contentSecurityPolicyManager = $this->getMockBuilder( + 'OC\Security\CSP\ContentSecurityPolicyManager') + ->disableOriginalConstructor() + ->getMock(); $this->middleware = $this->getMiddleware(true, true); $this->secException = new SecurityException('hey', false); $this->secAjaxException = new SecurityException('hey', true); @@ -91,7 +97,8 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->logger, 'files', $isLoggedIn, - $isAdminUser + $isAdminUser, + $this->contentSecurityPolicyManager ); } @@ -410,5 +417,31 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->assertTrue($response instanceof JSONResponse); } - + public function testAfterController() { + $response = $this->getMockBuilder('\OCP\AppFramework\Http\Response')->disableOriginalConstructor()->getMock(); + $defaultPolicy = new ContentSecurityPolicy(); + $defaultPolicy->addAllowedImageDomain('defaultpolicy'); + $currentPolicy = new ContentSecurityPolicy(); + $currentPolicy->addAllowedConnectDomain('currentPolicy'); + $mergedPolicy = new ContentSecurityPolicy(); + $mergedPolicy->addAllowedMediaDomain('mergedPolicy'); + $response + ->expects($this->exactly(2)) + ->method('getContentSecurityPolicy') + ->willReturn($currentPolicy); + $this->contentSecurityPolicyManager + ->expects($this->once()) + ->method('getDefaultPolicy') + ->willReturn($defaultPolicy); + $this->contentSecurityPolicyManager + ->expects($this->once()) + ->method('mergePolicies') + ->with($defaultPolicy, $currentPolicy) + ->willReturn($mergedPolicy); + $response->expects($this->once()) + ->method('setContentSecurityPolicy') + ->with($mergedPolicy); + + $this->middleware->afterController($this->controller, 'test', $response); + } } diff --git a/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php b/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php new file mode 100644 index 00000000000..975c35d3780 --- /dev/null +++ b/tests/lib/security/csp/ContentSecurityPolicyManagerTest.php @@ -0,0 +1,66 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +use OC\Security\CSP\ContentSecurityPolicyManager; + +class ContentSecurityPolicyManagerTest extends \Test\TestCase { + /** @var ContentSecurityPolicyManager */ + private $contentSecurityPolicyManager; + + public function setUp() { + parent::setUp(); + $this->contentSecurityPolicyManager = new ContentSecurityPolicyManager(); + } + + public function testAddDefaultPolicy() { + $this->contentSecurityPolicyManager->addDefaultPolicy(new \OCP\AppFramework\Http\ContentSecurityPolicy()); + } + + public function testGetDefaultPolicyWithPolicies() { + $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $policy->addAllowedFontDomain('mydomain.com'); + $policy->addAllowedImageDomain('anotherdomain.de'); + $this->contentSecurityPolicyManager->addDefaultPolicy($policy); + $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $policy->addAllowedFontDomain('example.com'); + $policy->addAllowedImageDomain('example.org'); + $policy->allowInlineScript(true); + $this->contentSecurityPolicyManager->addDefaultPolicy($policy); + $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy(); + $policy->addAllowedChildSrcDomain('childdomain'); + $policy->addAllowedFontDomain('anotherFontDomain'); + $this->contentSecurityPolicyManager->addDefaultPolicy($policy); + + $expected = new \OC\Security\CSP\ContentSecurityPolicy(); + $expected->allowInlineScript(true); + $expected->addAllowedFontDomain('mydomain.com'); + $expected->addAllowedFontDomain('example.com'); + $expected->addAllowedFontDomain('anotherFontDomain'); + $expected->addAllowedImageDomain('anotherdomain.de'); + $expected->addAllowedImageDomain('example.org'); + $expected->addAllowedChildSrcDomain('childdomain'); + $expectedStringPolicy = 'default-src \'none\';script-src \'self\' \'unsafe-inline\' \'unsafe-eval\';style-src \'self\' \'unsafe-inline\';img-src \'self\' data: blob: anotherdomain.de example.org;font-src \'self\' mydomain.com example.com anotherFontDomain;connect-src \'self\';media-src \'self\';child-src childdomain'; + + $this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy()); + $this->assertSame($expectedStringPolicy, $this->contentSecurityPolicyManager->getDefaultPolicy()->buildPolicy()); + } + +} diff --git a/tests/lib/server.php b/tests/lib/server.php index 8b2fec1f5a1..d13f9be0c9e 100644 --- a/tests/lib/server.php +++ b/tests/lib/server.php @@ -62,10 +62,12 @@ class Server extends \Test\TestCase { ['CapabilitiesManager', '\OC\CapabilitiesManager'], ['ContactsManager', '\OC\ContactsManager'], ['ContactsManager', '\OCP\Contacts\IManager'], + ['ContentSecurityPolicyManager', '\OC\Security\CSP\ContentSecurityPolicyManager'], ['CommentsManager', '\OCP\Comments\ICommentsManager'], ['Crypto', '\OC\Security\Crypto'], ['Crypto', '\OCP\Security\ICrypto'], ['CryptoWrapper', '\OC\Session\CryptoWrapper'], + ['CsrfTokenManager', '\OC\Security\CSRF\CsrfTokenManager'], ['DatabaseConnection', '\OC\DB\Connection'], ['DatabaseConnection', '\OCP\IDBConnection'], diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php index 45f2bedcb63..28b57435e1d 100644 --- a/tests/lib/share20/defaultshareprovidertest.php +++ b/tests/lib/share20/defaultshareprovidertest.php @@ -824,7 +824,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf()); $this->rootFolder->method('getById')->with(42)->willReturn([$file]); - $share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_USER, 1 , 0); + $share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_USER, null, 1 , 0); $this->assertCount(1, $share); $share = $share[0]; @@ -894,7 +894,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf()); $this->rootFolder->method('getById')->with(42)->willReturn([$file]); - $share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, 20 , 1); + $share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, null, 20 , 1); $this->assertCount(1, $share); $share = $share[0]; @@ -979,7 +979,7 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf()); $this->rootFolder->method('getById')->with(42)->willReturn([$file]); - $share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, -1, 0); + $share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, null, -1, 0); $this->assertCount(1, $share); $share = $share[0]; @@ -992,6 +992,78 @@ class DefaultShareProviderTest extends \Test\TestCase { $this->assertSame('userTarget', $share->getTarget()); } + public function testGetSharedWithUserWithNode() { + $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1', + 'file', 42, 'myTarget', 31, null, null, null); + $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1', + 'file', 43, 'myTarget', 31, null, null, null); + + $user0 = $this->getMock('\OCP\IUser'); + $user0->method('getUID')->willReturn('user0'); + $user1 = $this->getMock('\OCP\IUser'); + $user1->method('getUID')->willReturn('user1'); + + $this->userManager->method('get')->willReturnMap([ + ['user0', $user0], + ['user1', $user1], + ]); + + $file = $this->getMock('\OCP\Files\File'); + $file->method('getId')->willReturn(43); + $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf()); + $this->rootFolder->method('getById')->with(43)->willReturn([$file]); + + $share = $this->provider->getSharedWith($user0, \OCP\Share::SHARE_TYPE_USER, $file, -1, 0); + $this->assertCount(1, $share); + + $share = $share[0]; + $this->assertEquals($id, $share->getId()); + $this->assertSame($user0, $share->getSharedWith()); + $this->assertSame($user1, $share->getShareOwner()); + $this->assertSame($user1, $share->getSharedBy()); + $this->assertSame($file, $share->getNode()); + $this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType()); + } + + public function testGetSharedWithGroupWithNode() { + $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1', + 'file', 42, 'myTarget', 31, null, null, null); + $id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1', + 'file', 43, 'myTarget', 31, null, null, null); + + $user0 = $this->getMock('\OCP\IUser'); + $user0->method('getUID')->willReturn('user0'); + $user1 = $this->getMock('\OCP\IUser'); + $user1->method('getUID')->willReturn('user1'); + + $this->userManager->method('get')->willReturnMap([ + ['user0', $user0], + ['user1', $user1], + ]); + + $group0 = $this->getMock('\OCP\IGroup'); + $group0->method('getGID')->willReturn('group0'); + + $this->groupManager->method('get')->with('group0')->willReturn($group0); + $this->groupManager->method('getUserGroups')->with($user0)->willReturn([$group0]); + + $node = $this->getMock('\OCP\Files\Folder'); + $node->method('getId')->willReturn(43); + $this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf()); + $this->rootFolder->method('getById')->with(43)->willReturn([$node]); + + $share = $this->provider->getSharedWith($user0, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0); + $this->assertCount(1, $share); + + $share = $share[0]; + $this->assertEquals($id, $share->getId()); + $this->assertSame($group0, $share->getSharedWith()); + $this->assertSame($user1, $share->getShareOwner()); + $this->assertSame($user1, $share->getSharedBy()); + $this->assertSame($node, $share->getNode()); + $this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType()); + } + public function testGetSharesBy() { $qb = $this->dbConn->getQueryBuilder(); $qb->insert('share') |