diff --git a/packages/dynamite/dynamite/lib/src/builder/client.dart b/packages/dynamite/dynamite/lib/src/builder/client.dart index 16cac51c..51a4fefa 100644 --- a/packages/dynamite/dynamite/lib/src/builder/client.dart +++ b/packages/dynamite/dynamite/lib/src/builder/client.dart @@ -354,29 +354,7 @@ Iterable buildTags( nullable: dartParameterNullable, ).dartType; - if (result.name == 'String') { - if (parameter.schema?.pattern != null) { - code.write(''' -if (!RegExp(r'${parameter.schema!.pattern!}').hasMatch(${toDartName(parameter.name)})) { - throw Exception('Invalid value "\$${toDartName(parameter.name)}" for parameter "${toDartName(parameter.name)}" with pattern "\${r'${parameter.schema!.pattern!}'}"'); // coverage:ignore-line -} -'''); - } - if (parameter.schema?.minLength != null) { - code.write(''' -if (${toDartName(parameter.name)}.length < ${parameter.schema!.minLength!}) { - throw Exception('Parameter "${toDartName(parameter.name)}" has to be at least ${parameter.schema!.minLength!} characters long'); // coverage:ignore-line -} -'''); - } - if (parameter.schema?.maxLength != null) { - code.write(''' -if (${toDartName(parameter.name)}.length > ${parameter.schema!.maxLength!}) { - throw Exception('Parameter "${toDartName(parameter.name)}" has to be at most ${parameter.schema!.maxLength!} characters long'); // coverage:ignore-line -} -'''); - } - } + buildPatternCheck(result, parameter).forEach(code.writeln); final defaultValueCode = parameter.schema?.$default != null ? valueToEscapedValue(result, parameter.schema!.$default.toString()) @@ -610,6 +588,27 @@ final _response = await $client.doRequest( } } +Iterable buildPatternCheck( + final TypeResult result, + final openapi.Parameter parameter, +) sync* { + final value = toDartName(parameter.name); + final name = "'$value'"; + + final schema = parameter.schema; + if (result.name == 'String' && schema != null) { + if (schema.pattern != null) { + yield "checkPattern($value, RegExp(r'${schema.pattern!}'), $name); // coverage:ignore-line"; + } + if (schema.minLength != null) { + yield 'checkMinLength($value, ${schema.minLength}, $name); // coverage:ignore-line'; + } + if (schema.maxLength != null) { + yield 'checkMaxLength($value, ${schema.maxLength}, $name); // coverage:ignore-line'; + } + } +} + Iterable buildAuthCheck( final Map> responses, final MapEntry pathEntry, diff --git a/packages/dynamite/dynamite/lib/src/builder/imports.dart b/packages/dynamite/dynamite/lib/src/builder/imports.dart index 7e15b857..97c25371 100644 --- a/packages/dynamite/dynamite/lib/src/builder/imports.dart +++ b/packages/dynamite/dynamite/lib/src/builder/imports.dart @@ -17,6 +17,7 @@ List generateImports(final AssetId outputId) => [ Directive.import('package:collection/collection.dart'), Directive.import('package:dynamite_runtime/content_string.dart'), Directive.import('package:dynamite_runtime/http_client.dart'), + Directive.import('package:dynamite_runtime/utils.dart'), Directive.import('package:universal_io/io.dart'), const Code(''), Directive.export('package:dynamite_runtime/http_client.dart'), diff --git a/packages/dynamite/dynamite_runtime/lib/src/string_checker.dart b/packages/dynamite/dynamite_runtime/lib/src/string_checker.dart new file mode 100644 index 00000000..accfb49f --- /dev/null +++ b/packages/dynamite/dynamite_runtime/lib/src/string_checker.dart @@ -0,0 +1,26 @@ +/// Checks the [input] against [pattern]. +/// +/// Throws an `Exception` containing the [parameterName] if the `pattern` does not match. +void checkPattern(final String input, final RegExp pattern, final String parameterName) { + if (!pattern.hasMatch(input)) { + throw Exception('Invalid value "$input" for parameter "$parameterName" with pattern "${pattern.pattern}"'); + } +} + +/// Checks the [input] length against [minLength]. +/// +/// Throws an `Exception` containing the [parameterName] if the `input` is to short. +void checkMinLength(final String input, final int minLength, final String parameterName) { + if (input.length < minLength) { + throw Exception('Parameter "$input" has to be at least $minLength characters long'); + } +} + +/// Checks the [input] length against [maxLength]. +/// +/// Throws an `Exception` containing the [parameterName] if the `input` is to long. +void checkMaxLength(final String input, final int maxLength, final String parameterName) { + if (input.length > maxLength) { + throw Exception('Parameter "$input" has to be at most $maxLength characters long'); + } +} diff --git a/packages/dynamite/dynamite_runtime/lib/utils.dart b/packages/dynamite/dynamite_runtime/lib/utils.dart index 30f229d5..c8d7b711 100644 --- a/packages/dynamite/dynamite_runtime/lib/utils.dart +++ b/packages/dynamite/dynamite_runtime/lib/utils.dart @@ -1 +1,2 @@ +export 'src/string_checker.dart'; export 'src/uri.dart'; diff --git a/packages/nextcloud/lib/src/api/files.openapi.dart b/packages/nextcloud/lib/src/api/files.openapi.dart index d97ff316..af8b02b4 100644 --- a/packages/nextcloud/lib/src/api/files.openapi.dart +++ b/packages/nextcloud/lib/src/api/files.openapi.dart @@ -11,6 +11,7 @@ import 'package:built_value/standard_json_plugin.dart'; import 'package:collection/collection.dart'; import 'package:dynamite_runtime/content_string.dart'; import 'package:dynamite_runtime/http_client.dart'; +import 'package:dynamite_runtime/utils.dart'; import 'package:universal_io/io.dart'; export 'package:dynamite_runtime/http_client.dart'; @@ -120,9 +121,7 @@ class FilesApiClient { // coverage:ignore-end path = path.replaceAll('{x}', Uri.encodeQueryComponent(x.toString())); path = path.replaceAll('{y}', Uri.encodeQueryComponent(y.toString())); - if (!RegExp(r'^.+$').hasMatch(file)) { - throw Exception('Invalid value "$file" for parameter "file" with pattern "${r'^.+$'}"'); // coverage:ignore-line - } + checkPattern(file, RegExp(r'^.+$'), 'file'); // coverage:ignore-line path = path.replaceAll('{file}', Uri.encodeQueryComponent(file)); final response = await _rootClient.doRequest( 'get', diff --git a/packages/nextcloud/lib/src/api/files_reminders.openapi.dart b/packages/nextcloud/lib/src/api/files_reminders.openapi.dart index e0d6bb7e..ac6169fc 100644 --- a/packages/nextcloud/lib/src/api/files_reminders.openapi.dart +++ b/packages/nextcloud/lib/src/api/files_reminders.openapi.dart @@ -10,6 +10,7 @@ import 'package:built_value/standard_json_plugin.dart'; import 'package:collection/collection.dart'; import 'package:dynamite_runtime/content_string.dart'; import 'package:dynamite_runtime/http_client.dart'; +import 'package:dynamite_runtime/utils.dart'; import 'package:universal_io/io.dart'; export 'package:dynamite_runtime/http_client.dart'; @@ -109,11 +110,7 @@ class FilesRemindersApiClient { } // coverage:ignore-end - if (!RegExp(r'^1$').hasMatch(version)) { - throw Exception( - 'Invalid value "$version" for parameter "version" with pattern "${r'^1$'}"', - ); // coverage:ignore-line - } + checkPattern(version, RegExp(r'^1$'), 'version'); // coverage:ignore-line path = path.replaceAll('{version}', Uri.encodeQueryComponent(version)); path = path.replaceAll('{fileId}', Uri.encodeQueryComponent(fileId.toString())); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); @@ -164,11 +161,7 @@ class FilesRemindersApiClient { // coverage:ignore-end queryParameters['dueDate'] = dueDate; - if (!RegExp(r'^1$').hasMatch(version)) { - throw Exception( - 'Invalid value "$version" for parameter "version" with pattern "${r'^1$'}"', - ); // coverage:ignore-line - } + checkPattern(version, RegExp(r'^1$'), 'version'); // coverage:ignore-line path = path.replaceAll('{version}', Uri.encodeQueryComponent(version)); path = path.replaceAll('{fileId}', Uri.encodeQueryComponent(fileId.toString())); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); @@ -221,11 +214,7 @@ class FilesRemindersApiClient { } // coverage:ignore-end - if (!RegExp(r'^1$').hasMatch(version)) { - throw Exception( - 'Invalid value "$version" for parameter "version" with pattern "${r'^1$'}"', - ); // coverage:ignore-line - } + checkPattern(version, RegExp(r'^1$'), 'version'); // coverage:ignore-line path = path.replaceAll('{version}', Uri.encodeQueryComponent(version)); path = path.replaceAll('{fileId}', Uri.encodeQueryComponent(fileId.toString())); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); diff --git a/packages/nextcloud/lib/src/api/provisioning_api.openapi.dart b/packages/nextcloud/lib/src/api/provisioning_api.openapi.dart index 95fc8e16..ca925063 100644 --- a/packages/nextcloud/lib/src/api/provisioning_api.openapi.dart +++ b/packages/nextcloud/lib/src/api/provisioning_api.openapi.dart @@ -11,6 +11,7 @@ import 'package:built_value/standard_json_plugin.dart'; import 'package:collection/collection.dart'; import 'package:dynamite_runtime/content_string.dart'; import 'package:dynamite_runtime/http_client.dart'; +import 'package:dynamite_runtime/utils.dart'; import 'package:universal_io/io.dart'; export 'package:dynamite_runtime/http_client.dart'; @@ -733,11 +734,7 @@ class ProvisioningApiGroupsClient { } // coverage:ignore-end - if (!RegExp(r'^.+$').hasMatch(groupId)) { - throw Exception( - 'Invalid value "$groupId" for parameter "groupId" with pattern "${r'^.+$'}"', - ); // coverage:ignore-line - } + checkPattern(groupId, RegExp(r'^.+$'), 'groupId'); // coverage:ignore-line path = path.replaceAll('{groupId}', Uri.encodeQueryComponent(groupId)); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); final response = await _rootClient.doRequest( @@ -787,11 +784,7 @@ class ProvisioningApiGroupsClient { } // coverage:ignore-end - if (!RegExp(r'^.+$').hasMatch(groupId)) { - throw Exception( - 'Invalid value "$groupId" for parameter "groupId" with pattern "${r'^.+$'}"', - ); // coverage:ignore-line - } + checkPattern(groupId, RegExp(r'^.+$'), 'groupId'); // coverage:ignore-line path = path.replaceAll('{groupId}', Uri.encodeQueryComponent(groupId)); if (search != '') { queryParameters['search'] = search; @@ -849,11 +842,7 @@ class ProvisioningApiGroupsClient { } // coverage:ignore-end - if (!RegExp(r'^.+$').hasMatch(groupId)) { - throw Exception( - 'Invalid value "$groupId" for parameter "groupId" with pattern "${r'^.+$'}"', - ); // coverage:ignore-line - } + checkPattern(groupId, RegExp(r'^.+$'), 'groupId'); // coverage:ignore-line path = path.replaceAll('{groupId}', Uri.encodeQueryComponent(groupId)); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); final response = await _rootClient.doRequest( @@ -901,11 +890,7 @@ class ProvisioningApiGroupsClient { } // coverage:ignore-end - if (!RegExp(r'^.+$').hasMatch(groupId)) { - throw Exception( - 'Invalid value "$groupId" for parameter "groupId" with pattern "${r'^.+$'}"', - ); // coverage:ignore-line - } + checkPattern(groupId, RegExp(r'^.+$'), 'groupId'); // coverage:ignore-line path = path.replaceAll('{groupId}', Uri.encodeQueryComponent(groupId)); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); final response = await _rootClient.doRequest( @@ -958,11 +943,7 @@ class ProvisioningApiGroupsClient { // coverage:ignore-end queryParameters['key'] = key; queryParameters['value'] = value; - if (!RegExp(r'^.+$').hasMatch(groupId)) { - throw Exception( - 'Invalid value "$groupId" for parameter "groupId" with pattern "${r'^.+$'}"', - ); // coverage:ignore-line - } + checkPattern(groupId, RegExp(r'^.+$'), 'groupId'); // coverage:ignore-line path = path.replaceAll('{groupId}', Uri.encodeQueryComponent(groupId)); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); final response = await _rootClient.doRequest( @@ -1011,11 +992,7 @@ class ProvisioningApiGroupsClient { } // coverage:ignore-end - if (!RegExp(r'^.+$').hasMatch(groupId)) { - throw Exception( - 'Invalid value "$groupId" for parameter "groupId" with pattern "${r'^.+$'}"', - ); // coverage:ignore-line - } + checkPattern(groupId, RegExp(r'^.+$'), 'groupId'); // coverage:ignore-line path = path.replaceAll('{groupId}', Uri.encodeQueryComponent(groupId)); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); final response = await _rootClient.doRequest( @@ -1801,11 +1778,11 @@ class ProvisioningApiUsersClient { queryParameters['key'] = key; queryParameters['value'] = value; path = path.replaceAll('{userId}', Uri.encodeQueryComponent(userId)); - if (!RegExp(r'^(?!enable$|disable$)[a-zA-Z0-9_]*$').hasMatch(collectionName)) { - throw Exception( - 'Invalid value "$collectionName" for parameter "collectionName" with pattern "${r'^(?!enable$|disable$)[a-zA-Z0-9_]*$'}"', - ); // coverage:ignore-line - } + checkPattern( + collectionName, + RegExp(r'^(?!enable$|disable$)[a-zA-Z0-9_]*$'), + 'collectionName', + ); // coverage:ignore-line path = path.replaceAll('{collectionName}', Uri.encodeQueryComponent(collectionName)); headers['OCS-APIRequest'] = oCSAPIRequest.toString(); final response = await _rootClient.doRequest( diff --git a/packages/nextcloud/lib/src/api/theming.openapi.dart b/packages/nextcloud/lib/src/api/theming.openapi.dart index 66d75dcf..4ed2e605 100644 --- a/packages/nextcloud/lib/src/api/theming.openapi.dart +++ b/packages/nextcloud/lib/src/api/theming.openapi.dart @@ -11,6 +11,7 @@ import 'package:built_value/standard_json_plugin.dart'; import 'package:collection/collection.dart'; import 'package:dynamite_runtime/content_string.dart'; import 'package:dynamite_runtime/http_client.dart'; +import 'package:dynamite_runtime/utils.dart'; import 'package:universal_io/io.dart'; export 'package:dynamite_runtime/http_client.dart'; @@ -186,9 +187,7 @@ class ThemingIconClient { // coverage:ignore-end path = path.replaceAll('{app}', Uri.encodeQueryComponent(app)); - if (!RegExp(r'^.+$').hasMatch(image)) { - throw Exception('Invalid value "$image" for parameter "image" with pattern "${r'^.+$'}"'); // coverage:ignore-line - } + checkPattern(image, RegExp(r'^.+$'), 'image'); // coverage:ignore-line path = path.replaceAll('{image}', Uri.encodeQueryComponent(image)); final response = await _rootClient.doRequest( 'get',