mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
feat: add support for sensitive Declarative settings values encryption
Signed-off-by: Andrey Borysenko <andrey18106x@gmail.com>
This commit is contained in:
parent
1d4b899244
commit
7994332338
13 changed files with 610 additions and 7 deletions
|
|
@ -67,6 +67,7 @@ return [
|
|||
],
|
||||
'ocs' => [
|
||||
['name' => 'DeclarativeSettings#setValue', 'url' => '/settings/api/declarative/value', 'verb' => 'POST', 'root' => ''],
|
||||
['name' => 'DeclarativeSettings#setSensitiveValue', 'url' => '/settings/api/declarative/value-sensitive', 'verb' => 'POST', 'root' => ''],
|
||||
['name' => 'DeclarativeSettings#getForms', 'url' => '/settings/api/declarative/forms', 'verb' => 'GET', 'root' => ''],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -144,6 +144,14 @@ trait CommonSettingsTrait {
|
|||
$this->declarativeSettingsManager->loadSchemas();
|
||||
$declarativeSettings = $this->declarativeSettingsManager->getFormsWithValues($user, $type, $section);
|
||||
|
||||
foreach ($declarativeSettings as &$form) {
|
||||
foreach ($form['fields'] as &$field) {
|
||||
if (isset($field['sensitive']) && $field['sensitive'] === true && !empty($field['value'])) {
|
||||
$field['value'] = 'dummySecret';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($type === 'personal') {
|
||||
$settings = array_values($this->settingsManager->getPersonalSettings($section));
|
||||
if ($section === 'theming') {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
|
|||
use OCA\Settings\ResponseDefinitions;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCS\OCSBadRequestException;
|
||||
use OCP\AppFramework\OCSController;
|
||||
|
|
@ -53,6 +54,45 @@ class DeclarativeSettingsController extends OCSController {
|
|||
*/
|
||||
#[NoAdminRequired]
|
||||
public function setValue(string $app, string $formId, string $fieldId, mixed $value): DataResponse {
|
||||
return $this->saveValue($app, $formId, $fieldId, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a declarative settings value.
|
||||
* Password confirmation is required for sensitive values.
|
||||
*
|
||||
* @param string $app ID of the app
|
||||
* @param string $formId ID of the form
|
||||
* @param string $fieldId ID of the field
|
||||
* @param mixed $value Value to be saved
|
||||
* @return DataResponse<Http::STATUS_OK, null, array{}>
|
||||
* @throws NotLoggedInException Not logged in or not an admin user
|
||||
* @throws NotAdminException Not logged in or not an admin user
|
||||
* @throws OCSBadRequestException Invalid arguments to save value
|
||||
*
|
||||
* 200: Value set successfully
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
#[PasswordConfirmationRequired]
|
||||
public function setSensitiveValue(string $app, string $formId, string $fieldId, mixed $value): DataResponse {
|
||||
return $this->saveValue($app, $formId, $fieldId, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a declarative settings value.
|
||||
*
|
||||
* @param string $app ID of the app
|
||||
* @param string $formId ID of the form
|
||||
* @param string $fieldId ID of the field
|
||||
* @param mixed $value Value to be saved
|
||||
* @return DataResponse<Http::STATUS_OK, null, array{}>
|
||||
* @throws NotLoggedInException Not logged in or not an admin user
|
||||
* @throws NotAdminException Not logged in or not an admin user
|
||||
* @throws OCSBadRequestException Invalid arguments to save value
|
||||
*
|
||||
* 200: Value set successfully
|
||||
*/
|
||||
private function saveValue(string $app, string $formId, string $fieldId, mixed $value): DataResponse {
|
||||
$user = $this->userSession->getUser();
|
||||
if ($user === null) {
|
||||
throw new NotLoggedInException();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace OCA\Settings;
|
|||
* default: mixed,
|
||||
* options?: list<string|array{name: string, value: mixed}>,
|
||||
* value: string|int|float|bool|list<string>,
|
||||
* sensitive?: boolean,
|
||||
* }
|
||||
*
|
||||
* @psalm-type SettingsDeclarativeForm = array{
|
||||
|
|
|
|||
|
|
@ -169,6 +169,9 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"sensitive": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -373,6 +376,140 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/settings/api/declarative/value-sensitive": {
|
||||
"post": {
|
||||
"operationId": "declarative_settings-set-sensitive-value",
|
||||
"summary": "Sets a declarative settings value. Password confirmation is required for sensitive values.",
|
||||
"description": "This endpoint requires password confirmation",
|
||||
"tags": [
|
||||
"declarative_settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"app",
|
||||
"formId",
|
||||
"fieldId",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"app": {
|
||||
"type": "string",
|
||||
"description": "ID of the app"
|
||||
},
|
||||
"formId": {
|
||||
"type": "string",
|
||||
"description": "ID of the form"
|
||||
},
|
||||
"fieldId": {
|
||||
"type": "string",
|
||||
"description": "ID of the field"
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "Value to be saved"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Value set successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Not logged in or not an admin user",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid arguments to save value",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/settings/api/declarative/forms": {
|
||||
"get": {
|
||||
"operationId": "declarative_settings-get-forms",
|
||||
|
|
|
|||
|
|
@ -169,6 +169,9 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"sensitive": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -332,6 +335,140 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/settings/api/declarative/value-sensitive": {
|
||||
"post": {
|
||||
"operationId": "declarative_settings-set-sensitive-value",
|
||||
"summary": "Sets a declarative settings value. Password confirmation is required for sensitive values.",
|
||||
"description": "This endpoint requires password confirmation",
|
||||
"tags": [
|
||||
"declarative_settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"app",
|
||||
"formId",
|
||||
"fieldId",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"app": {
|
||||
"type": "string",
|
||||
"description": "ID of the app"
|
||||
},
|
||||
"formId": {
|
||||
"type": "string",
|
||||
"description": "ID of the form"
|
||||
},
|
||||
"fieldId": {
|
||||
"type": "string",
|
||||
"description": "ID of the field"
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "Value to be saved"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Value set successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Not logged in or not an admin user",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid arguments to save value",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/settings/api/declarative/forms": {
|
||||
"get": {
|
||||
"operationId": "declarative_settings-get-forms",
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
|
|||
import NcInputField from '@nextcloud/vue/components/NcInputField'
|
||||
import NcSelect from '@nextcloud/vue/components/NcSelect'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import { confirmPassword } from '@nextcloud/password-confirmation'
|
||||
|
||||
export default {
|
||||
name: 'DeclarativeSection',
|
||||
|
|
@ -202,9 +203,19 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
updateDeclarativeSettingsValue(formField, value = null) {
|
||||
async updateDeclarativeSettingsValue(formField, value = null) {
|
||||
try {
|
||||
return axios.post(generateOcsUrl('settings/api/declarative/value'), {
|
||||
let url = generateOcsUrl('settings/api/declarative/value')
|
||||
if (formField?.sensitive === true) {
|
||||
url = generateOcsUrl('settings/api/declarative/value-sensitive')
|
||||
try {
|
||||
await confirmPassword()
|
||||
} catch (err) {
|
||||
showError(t('settings', 'Password confirmation is required'))
|
||||
return
|
||||
}
|
||||
}
|
||||
return axios.post(url, {
|
||||
app: this.formApp,
|
||||
formId: this.form.id.replace(this.formApp + '_', ''), // Remove app prefix to send clean form id
|
||||
fieldId: formField.id,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ interface DeclarativeFormField {
|
|||
options: Array<unknown>|null,
|
||||
value: unknown,
|
||||
default: unknown,
|
||||
sensitive: boolean,
|
||||
}
|
||||
|
||||
interface DeclarativeForm {
|
||||
|
|
|
|||
|
|
@ -169,6 +169,36 @@ class DeclarativeSettingsForm implements IDeclarativeSettingsForm {
|
|||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'test_sensitive_field',
|
||||
'title' => 'Sensitive text field',
|
||||
'description' => 'Set some secure value setting that is stored encrypted',
|
||||
'type' => DeclarativeSettingsTypes::TEXT,
|
||||
'label' => 'Sensitive field',
|
||||
'placeholder' => 'Set secure value',
|
||||
'default' => '',
|
||||
'sensitive' => true, // only for TEXT, PASSWORD types
|
||||
],
|
||||
[
|
||||
'id' => 'test_sensitive_field_2',
|
||||
'title' => 'Sensitive password field',
|
||||
'description' => 'Set some password setting that is stored encrypted',
|
||||
'type' => DeclarativeSettingsTypes::PASSWORD,
|
||||
'label' => 'Sensitive field',
|
||||
'placeholder' => 'Set secure value',
|
||||
'default' => '',
|
||||
'sensitive' => true, // only for TEXT, PASSWORD types
|
||||
],
|
||||
[
|
||||
'id' => 'test_non_sensitive_field',
|
||||
'title' => 'Password field',
|
||||
'description' => 'Set some password setting',
|
||||
'type' => DeclarativeSettingsTypes::PASSWORD,
|
||||
'label' => 'Password field',
|
||||
'placeholder' => 'Set secure value',
|
||||
'default' => '',
|
||||
'sensitive' => false,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use OCP\IAppConfig;
|
|||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\Security\ICrypto;
|
||||
use OCP\Server;
|
||||
use OCP\Settings\DeclarativeSettingsTypes;
|
||||
use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
|
||||
|
|
@ -49,6 +50,7 @@ class DeclarativeManager implements IDeclarativeManager {
|
|||
private IConfig $config,
|
||||
private IAppConfig $appConfig,
|
||||
private LoggerInterface $logger,
|
||||
private ICrypto $crypto,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -266,7 +268,7 @@ class DeclarativeManager implements IDeclarativeManager {
|
|||
$this->eventDispatcher->dispatchTyped(new DeclarativeSettingsSetValueEvent($user, $app, $formId, $fieldId, $value));
|
||||
break;
|
||||
case DeclarativeSettingsTypes::STORAGE_TYPE_INTERNAL:
|
||||
$this->saveInternalValue($user, $app, $fieldId, $value);
|
||||
$this->saveInternalValue($user, $app, $formId, $fieldId, $value);
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Unknown storage type "' . $storageType . '"');
|
||||
|
|
@ -290,18 +292,52 @@ class DeclarativeManager implements IDeclarativeManager {
|
|||
private function getInternalValue(IUser $user, string $app, string $formId, string $fieldId): mixed {
|
||||
$sectionType = $this->getSectionType($app, $fieldId);
|
||||
$defaultValue = $this->getDefaultValue($app, $formId, $fieldId);
|
||||
|
||||
$field = $this->getSchemaField($app, $formId, $fieldId);
|
||||
$isSensitive = $field !== null && isset($field['sensitive']) && $field['sensitive'] === true;
|
||||
|
||||
switch ($sectionType) {
|
||||
case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN:
|
||||
return $this->config->getAppValue($app, $fieldId, $defaultValue);
|
||||
$value = $this->config->getAppValue($app, $fieldId, $defaultValue);
|
||||
break;
|
||||
case DeclarativeSettingsTypes::SECTION_TYPE_PERSONAL:
|
||||
return $this->config->getUserValue($user->getUID(), $app, $fieldId, $defaultValue);
|
||||
$value = $this->config->getUserValue($user->getUID(), $app, $fieldId, $defaultValue);
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Unknown section type "' . $sectionType . '"');
|
||||
}
|
||||
if ($isSensitive && $value !== '') {
|
||||
try {
|
||||
$value = $this->crypto->decrypt($value);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->warning('Failed to decrypt sensitive value for field {field} in app {app}: {message}', [
|
||||
'field' => $fieldId,
|
||||
'app' => $app,
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
$value = $defaultValue;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function saveInternalValue(IUser $user, string $app, string $fieldId, mixed $value): void {
|
||||
private function saveInternalValue(IUser $user, string $app, string $formId, string $fieldId, mixed $value): void {
|
||||
$sectionType = $this->getSectionType($app, $fieldId);
|
||||
|
||||
$field = $this->getSchemaField($app, $formId, $fieldId);
|
||||
if ($field !== null && isset($field['sensitive']) && $field['sensitive'] === true && $value !== '' && $value !== 'dummySecret') {
|
||||
try {
|
||||
$value = $this->crypto->encrypt($value);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->warning('Failed to decrypt sensitive value for field {field} in app {app}: {message}', [
|
||||
'field' => $fieldId,
|
||||
'app' => $app,
|
||||
'message' => $e->getMessage()]
|
||||
);
|
||||
throw new Exception('Failed to encrypt sensitive value');
|
||||
}
|
||||
}
|
||||
|
||||
switch ($sectionType) {
|
||||
case DeclarativeSettingsTypes::SECTION_TYPE_ADMIN:
|
||||
$this->appConfig->setValueString($app, $fieldId, $value);
|
||||
|
|
@ -314,6 +350,27 @@ class DeclarativeManager implements IDeclarativeManager {
|
|||
}
|
||||
}
|
||||
|
||||
private function getSchemaField(string $app, string $formId, string $fieldId): ?array {
|
||||
$form = $this->getForm($app, $formId);
|
||||
if ($form !== null) {
|
||||
foreach ($form->getSchema()['fields'] as $field) {
|
||||
if ($field['id'] === $fieldId) {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($this->appSchemas[$app] ?? [] as $schema) {
|
||||
if ($schema['id'] === $formId) {
|
||||
foreach ($schema['fields'] as $field) {
|
||||
if ($field['id'] === $fieldId) {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getDefaultValue(string $app, string $formId, string $fieldId): mixed {
|
||||
foreach ($this->appSchemas[$app] as $schema) {
|
||||
if ($schema['id'] === $formId) {
|
||||
|
|
@ -391,6 +448,12 @@ class DeclarativeManager implements IDeclarativeManager {
|
|||
]);
|
||||
return false;
|
||||
}
|
||||
if (isset($field['sensitive']) && $field['sensitive'] === true && !in_array($field['type'], [DeclarativeSettingsTypes::TEXT, DeclarativeSettingsTypes::PASSWORD])) {
|
||||
$this->logger->warning('Declarative settings: sensitive field type is supported only for TEXT and PASSWORD types ({app}, {form_id}, {field_id})', [
|
||||
'app' => $appId, 'form_id' => $formId, 'field_id' => $fieldId,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
if (!$this->validateField($appId, $formId, $field)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ namespace OCP\Settings;
|
|||
* label?: string,
|
||||
* default: mixed,
|
||||
* options?: list<string|array{name: string, value: mixed}>,
|
||||
* sensitive?: boolean,
|
||||
* }
|
||||
*
|
||||
* @psalm-type DeclarativeSettingsFormFieldWithValue = DeclarativeSettingsFormField&array{
|
||||
|
|
|
|||
137
openapi.json
137
openapi.json
|
|
@ -3981,6 +3981,9 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"sensitive": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -27197,6 +27200,140 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/settings/api/declarative/value-sensitive": {
|
||||
"post": {
|
||||
"operationId": "settings-declarative_settings-set-sensitive-value",
|
||||
"summary": "Sets a declarative settings value. Password confirmation is required for sensitive values.",
|
||||
"description": "This endpoint requires password confirmation",
|
||||
"tags": [
|
||||
"settings/declarative_settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"app",
|
||||
"formId",
|
||||
"fieldId",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"app": {
|
||||
"type": "string",
|
||||
"description": "ID of the app"
|
||||
},
|
||||
"formId": {
|
||||
"type": "string",
|
||||
"description": "ID of the form"
|
||||
},
|
||||
"fieldId": {
|
||||
"type": "string",
|
||||
"description": "ID of the field"
|
||||
},
|
||||
"value": {
|
||||
"type": "object",
|
||||
"description": "Value to be saved"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Value set successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Not logged in or not an admin user",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid arguments to save value",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/settings/api/declarative/forms": {
|
||||
"get": {
|
||||
"operationId": "settings-declarative_settings-get-forms",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use OCP\IAppConfig;
|
|||
use OCP\IConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\Security\ICrypto;
|
||||
use OCP\Settings\DeclarativeSettingsTypes;
|
||||
use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
|
||||
use OCP\Settings\IDeclarativeManager;
|
||||
|
|
@ -50,6 +51,9 @@ class DeclarativeManagerTest extends TestCase {
|
|||
/** @var LoggerInterface|MockObject */
|
||||
private $logger;
|
||||
|
||||
/** @var ICrypto|MockObject */
|
||||
private $crypto;
|
||||
|
||||
/** @var IUser|MockObject */
|
||||
private $user;
|
||||
|
||||
|
|
@ -215,6 +219,36 @@ class DeclarativeManagerTest extends TestCase {
|
|||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'id' => 'test_sensitive_field',
|
||||
'title' => 'Sensitive text field',
|
||||
'description' => 'Set some secure value setting that is stored encrypted',
|
||||
'type' => DeclarativeSettingsTypes::TEXT,
|
||||
'label' => 'Sensitive field',
|
||||
'placeholder' => 'Set secure value',
|
||||
'default' => '',
|
||||
'sensitive' => true, // only for TEXT, PASSWORD types
|
||||
],
|
||||
[
|
||||
'id' => 'test_sensitive_field_2',
|
||||
'title' => 'Sensitive password field',
|
||||
'description' => 'Set some password setting that is stored encrypted',
|
||||
'type' => DeclarativeSettingsTypes::PASSWORD,
|
||||
'label' => 'Sensitive field',
|
||||
'placeholder' => 'Set secure value',
|
||||
'default' => '',
|
||||
'sensitive' => true, // only for TEXT, PASSWORD types
|
||||
],
|
||||
[
|
||||
'id' => 'test_non_sensitive_field',
|
||||
'title' => 'Password field',
|
||||
'description' => 'Set some password setting',
|
||||
'type' => DeclarativeSettingsTypes::PASSWORD,
|
||||
'label' => 'Password field',
|
||||
'placeholder' => 'Set secure value',
|
||||
'default' => '',
|
||||
'sensitive' => false,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
|
|
@ -229,6 +263,7 @@ class DeclarativeManagerTest extends TestCase {
|
|||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->appConfig = $this->createMock(IAppConfig::class);
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->crypto = $this->createMock(ICrypto::class);
|
||||
|
||||
$this->declarativeManager = new DeclarativeManager(
|
||||
$this->eventDispatcher,
|
||||
|
|
@ -236,7 +271,8 @@ class DeclarativeManagerTest extends TestCase {
|
|||
$this->coordinator,
|
||||
$this->config,
|
||||
$this->appConfig,
|
||||
$this->logger
|
||||
$this->logger,
|
||||
$this->crypto,
|
||||
);
|
||||
|
||||
$this->user = $this->createMock(IUser::class);
|
||||
|
|
|
|||
Loading…
Reference in a new issue