From 2fa0758e3ee2bb3685d59718ffdbc8d147515103 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Tue, 4 Apr 2023 15:21:07 +0200 Subject: [PATCH 1/2] dynamite: Support per operation security --- .../dynamite/lib/src/models/operation.dart | 4 + .../dynamite/lib/src/models/operation.g.dart | 9 +- .../dynamite/lib/src/openapi_builder.dart | 263 +++++++++++------- 3 files changed, 167 insertions(+), 109 deletions(-) diff --git a/packages/dynamite/lib/src/models/operation.dart b/packages/dynamite/lib/src/models/operation.dart index cc5fa669..765deb01 100644 --- a/packages/dynamite/lib/src/models/operation.dart +++ b/packages/dynamite/lib/src/models/operation.dart @@ -2,6 +2,7 @@ import 'package:dynamite/src/models/parameter.dart'; import 'package:dynamite/src/models/request_body.dart'; import 'package:dynamite/src/models/response.dart'; import 'package:dynamite/src/models/responses.dart'; +import 'package:dynamite/src/models/security_requirement.dart'; import 'package:json_annotation/json_annotation.dart'; part 'operation.g.dart'; @@ -17,6 +18,7 @@ class Operation { this.parameters, this.requestBody, this.responses, + this.security, }); factory Operation.fromJson(final Map json) => _$OperationFromJson(json); @@ -37,4 +39,6 @@ class Operation { final RequestBody? requestBody; final Responses? responses; + + final List? security; } diff --git a/packages/dynamite/lib/src/models/operation.g.dart b/packages/dynamite/lib/src/models/operation.g.dart index 7b1ad93b..dad48fe6 100644 --- a/packages/dynamite/lib/src/models/operation.g.dart +++ b/packages/dynamite/lib/src/models/operation.g.dart @@ -17,7 +17,8 @@ Operation _$OperationFromJson(Map json) { 'tags', 'parameters', 'requestBody', - 'responses' + 'responses', + 'security' ], ); return Operation( @@ -32,6 +33,11 @@ Operation _$OperationFromJson(Map json) { responses: (json['responses'] as Map?)?.map( (k, e) => MapEntry(k, Response.fromJson(e as Map)), ), + security: (json['security'] as List?) + ?.map((e) => (e as Map).map( + (k, e) => MapEntry(k, (e as List).map((e) => e as String).toList()), + )) + .toList(), ); } @@ -52,5 +58,6 @@ Map _$OperationToJson(Operation instance) { writeNotNull('parameters', instance.parameters?.map((e) => e.toJson()).toList()); writeNotNull('requestBody', instance.requestBody?.toJson()); writeNotNull('responses', instance.responses?.map((k, e) => MapEntry(k, e.toJson()))); + writeNotNull('security', instance.security); return val; } diff --git a/packages/dynamite/lib/src/openapi_builder.dart b/packages/dynamite/lib/src/openapi_builder.dart index 33939b6b..813ab987 100644 --- a/packages/dynamite/lib/src/openapi_builder.dart +++ b/packages/dynamite/lib/src/openapi_builder.dart @@ -55,7 +55,7 @@ class OpenAPIBuilder implements Builder { : a.compareTo(b), ); - final hasAnySecurity = spec.security?.isNotEmpty ?? false; + final hasAnySecurity = spec.components?.securitySchemes?.isNotEmpty ?? false; final state = State(prefix); final output = [ @@ -255,128 +255,152 @@ class OpenAPIBuilder implements Builder { (final b) => b ..name = '${prefix}Authentication' ..abstract = true - ..methods.add( + ..methods.addAll([ + Method( + (final b) => b + ..name = 'id' + ..type = MethodType.getter + ..returns = refer('String'), + ), Method( (final b) => b ..name = 'headers' ..type = MethodType.getter ..returns = refer('Map'), ), - ), + ]), ).accept(emitter).toString(), ], ]; - if (spec.security != null) { - for (final securityRequirement in spec.security!) { - for (final name in securityRequirement.keys) { - final securityScheme = spec.components!.securitySchemes![name]!; - switch (securityScheme.type) { - case 'http': - switch (securityScheme.scheme) { - case 'basic': - output.add( - Class( - (final b) { - final fields = ['username', 'password']; - b - ..name = '${prefix}HttpBasicAuthentication' - ..extend = refer('${prefix}Authentication') - ..constructors.add( - Constructor( - (final b) => b - ..optionalParameters.addAll( - fields.map( - (final name) => Parameter( - (final b) => b - ..name = name - ..toThis = true - ..named = true - ..required = true, - ), - ), - ), - ), - ) - ..fields.addAll( - fields.map( - (final name) => Field( - (final b) => b - ..name = name - ..type = refer('String') - ..modifier = FieldModifier.final$, - ), - ), - ) - ..methods.add( - Method( - (final b) => b - ..name = 'headers' - ..type = MethodType.getter - ..returns = refer('Map') - ..lambda = true - ..body = const Code(r''' - { - 'Authorization': 'Basic ${base64.encode(utf8.encode('$username:$password'))}', - } - '''), - ), - ); - }, - ).accept(emitter).toString(), - ); - continue; - case 'bearer': - output.add( - Class( - (final b) { - b - ..name = '${prefix}HttpBearerAuthentication' - ..extend = refer('${prefix}Authentication') - ..constructors.add( - Constructor( - (final b) => b - ..optionalParameters.add( - Parameter( + if (spec.components?.securitySchemes != null) { + for (final name in spec.components!.securitySchemes!.keys) { + final securityScheme = spec.components!.securitySchemes![name]!; + switch (securityScheme.type) { + case 'http': + switch (securityScheme.scheme) { + case 'basic': + output.add( + Class( + (final b) { + final fields = ['username', 'password']; + b + ..name = '${prefix}HttpBasicAuthentication' + ..extend = refer('${prefix}Authentication') + ..constructors.add( + Constructor( + (final b) => b + ..optionalParameters.addAll( + fields.map( + (final name) => Parameter( (final b) => b - ..name = 'token' + ..name = name ..toThis = true ..named = true ..required = true, ), ), - ), - ) - ..fields.add( - Field( + ), + ), + ) + ..fields.addAll( + fields.map( + (final name) => Field( (final b) => b - ..name = 'token' + ..name = name ..type = refer('String') ..modifier = FieldModifier.final$, ), - ) - ..methods.add( - Method( - (final b) => b - ..name = 'headers' - ..type = MethodType.getter - ..returns = refer('Map') - ..lambda = true - ..body = const Code(r''' + ), + ) + ..methods.addAll([ + Method( + (final b) => b + ..name = 'id' + ..annotations.add(refer('override')) + ..type = MethodType.getter + ..lambda = true + ..returns = refer('String') + ..body = Code("'$name'"), + ), + Method( + (final b) => b + ..name = 'headers' + ..annotations.add(refer('override')) + ..type = MethodType.getter + ..returns = refer('Map') + ..lambda = true + ..body = const Code(r''' + { + 'Authorization': 'Basic ${base64.encode(utf8.encode('$username:$password'))}', + } + '''), + ), + ]); + }, + ).accept(emitter).toString(), + ); + continue; + case 'bearer': + output.add( + Class( + (final b) { + b + ..name = '${prefix}HttpBearerAuthentication' + ..extend = refer('${prefix}Authentication') + ..constructors.add( + Constructor( + (final b) => b + ..optionalParameters.add( + Parameter( + (final b) => b + ..name = 'token' + ..toThis = true + ..named = true + ..required = true, + ), + ), + ), + ) + ..fields.addAll([ + Field( + (final b) => b + ..name = 'token' + ..type = refer('String') + ..modifier = FieldModifier.final$, + ), + ]) + ..methods.addAll([ + Method( + (final b) => b + ..name = 'id' + ..annotations.add(refer('override')) + ..type = MethodType.getter + ..lambda = true + ..returns = refer('String') + ..body = Code("'$name'"), + ), + Method( + (final b) => b + ..name = 'headers' + ..annotations.add(refer('override')) + ..type = MethodType.getter + ..returns = refer('Map') + ..lambda = true + ..body = const Code(r''' { 'Authorization': 'Bearer $token', } '''), - ), - ); - }, - ).accept(emitter).toString(), - ); - continue; - } - } - throw Exception('Can not work with security scheme ${securityScheme.toJson()}'); + ), + ]); + }, + ).accept(emitter).toString(), + ); + continue; + } } + throw Exception('Can not work with security scheme ${securityScheme.toJson()}'); } } @@ -438,8 +462,8 @@ class OpenAPIBuilder implements Builder { if (hasAnySecurity) ...[ Field( (final b) => b - ..name = 'authentication' - ..type = refer('${prefix}Authentication?') + ..name = 'authentications' + ..type = refer('List<${prefix}Authentication>') ..modifier = FieldModifier.final$, ), ], @@ -482,22 +506,18 @@ class OpenAPIBuilder implements Builder { if (hasAnySecurity) ...[ Parameter( (final b) => b - ..name = 'authentication' + ..name = 'authentications' ..toThis = true - ..named = true, + ..named = true + ..defaultTo = const Code('const []'), ), ], ]) - ..body = Code(''' + ..body = const Code(''' this.baseHeaders = { if (baseHeaders != null) ...{ ...baseHeaders, }, - ${hasAnySecurity ? ''' - if (authentication != null) ...{ - ...authentication!.headers, - }, - ''' : ''} }; this.httpClient = (httpClient ?? HttpClient())..userAgent = userAgent; '''), @@ -651,6 +671,33 @@ class OpenAPIBuilder implements Builder { Uint8List? body; '''); + final securityRequirements = + (operation.security ?? spec.security) ?? >>[]; + final isOptionalSecurity = + securityRequirements.where((final requirement) => requirement.keys.isEmpty).isNotEmpty; + if (isOptionalSecurity) { + code.write(''' + if (${isRootClient ? '' : 'rootClient.'}authentications.isNotEmpty) { + headers.addAll(${isRootClient ? '' : 'rootClient.'}authentications.first.headers); + } + '''); + } else { + for (final requirement in securityRequirements) { + code.write(''' + if (${isRootClient ? '' : 'rootClient.'}authentications.map((final a) => a.id).contains('${requirement.keys.single}')) { + headers.addAll(${isRootClient ? '' : 'rootClient.'}authentications.singleWhere((final a) => a.id == '${requirement.keys.single}').headers); + } else + '''); + } + if (securityRequirements.isNotEmpty) { + code.write(''' + { + throw Exception('Missing authentication for ${securityRequirements.map((final r) => r.keys.single).join(' or ')}'); + } + '''); + } + } + for (final parameter in parameters) { final nullable = _isParameterNullable( parameter.required, From 97965e2043dc8c1e032bfa9d1210d0a9d4ef80b1 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Tue, 4 Apr 2023 15:30:39 +0200 Subject: [PATCH 2/2] nextcloud,specs: Adapt to per operation security --- packages/nextcloud/lib/src/client.dart | 14 +- .../nextcloud/lib/src/nextcloud.openapi.dart | 321 +++++++++++++++++- .../nextcloud/lib/src/nextcloud.openapi.json | 1 + packages/nextcloud/lib/src/webdav/client.dart | 1 + specs/core.json | 1 + 5 files changed, 327 insertions(+), 11 deletions(-) diff --git a/packages/nextcloud/lib/src/client.dart b/packages/nextcloud/lib/src/client.dart index 4821ce9d..d761eea7 100644 --- a/packages/nextcloud/lib/src/client.dart +++ b/packages/nextcloud/lib/src/client.dart @@ -20,12 +20,14 @@ class NextcloudClient extends openapi.NextcloudClient { }..removeWhere((final _, final value) => value == null)) .cast(), userAgent: userAgentOverride ?? appType.userAgent, - authentication: loginName != null && password != null - ? openapi.NextcloudHttpBasicAuthentication( - username: loginName, - password: password, - ) - : null, + authentications: [ + if (loginName != null && password != null) ...[ + openapi.NextcloudHttpBasicAuthentication( + username: loginName, + password: password, + ), + ], + ], ); /// Identifier used for authentication. This can be the username or email or something else. diff --git a/packages/nextcloud/lib/src/nextcloud.openapi.dart b/packages/nextcloud/lib/src/nextcloud.openapi.dart index 1025253a..e266e72f 100644 --- a/packages/nextcloud/lib/src/nextcloud.openapi.dart +++ b/packages/nextcloud/lib/src/nextcloud.openapi.dart @@ -71,6 +71,7 @@ class NextcloudApiException extends _Response implements Exception { } abstract class NextcloudAuthentication { + String get id; Map get headers; } @@ -84,6 +85,9 @@ class NextcloudHttpBasicAuthentication extends NextcloudAuthentication { final String password; + @override + String get id => 'basic_auth'; + @override Map get headers => { 'Authorization': 'Basic ${base64.encode(utf8.encode('$username:$password'))}', }; @@ -96,15 +100,12 @@ class NextcloudClient { String? userAgent, HttpClient? httpClient, this.cookieJar, - this.authentication, + this.authentications = const [], }) { this.baseHeaders = { if (baseHeaders != null) ...{ ...baseHeaders, }, - if (authentication != null) ...{ - ...authentication!.headers, - }, }; this.httpClient = (httpClient ?? HttpClient())..userAgent = userAgent; } @@ -117,7 +118,7 @@ class NextcloudClient { final CookieJar? cookieJar; - final NextcloudAuthentication? authentication; + final List authentications; Future<_Response> doRequest( String method, @@ -193,6 +194,11 @@ class NextcloudCoreClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -213,6 +219,11 @@ class NextcloudCoreClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -233,6 +244,11 @@ class NextcloudCoreClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'post', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -253,6 +269,11 @@ class NextcloudCoreClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['token'] = token; final response = await rootClient.doRequest( 'post', @@ -281,6 +302,11 @@ class NextcloudCoreClient { 'Accept': 'image/png', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } if (file != '') { queryParameters['file'] = file; } @@ -321,6 +347,11 @@ class NextcloudCoreClient { 'Accept': 'image/png', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{userId}', Uri.encodeQueryComponent(userId)); path = path.replaceAll('{size}', Uri.encodeQueryComponent(size.toString())); final response = await rootClient.doRequest( @@ -345,6 +376,11 @@ class NextcloudCoreClient { 'Accept': 'image/png', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{userId}', Uri.encodeQueryComponent(userId)); path = path.replaceAll('{size}', Uri.encodeQueryComponent(size.toString())); final response = await rootClient.doRequest( @@ -373,6 +409,11 @@ class NextcloudCoreClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['search'] = search; queryParameters['itemType'] = itemType; queryParameters['itemId'] = itemId; @@ -409,6 +450,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -429,6 +475,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -449,6 +500,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['name'] = name; final response = await rootClient.doRequest( 'post', @@ -471,6 +527,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{folderId}', Uri.encodeQueryComponent(folderId.toString())); queryParameters['name'] = name; final response = await rootClient.doRequest( @@ -490,6 +551,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{folderId}', Uri.encodeQueryComponent(folderId.toString())); final response = await rootClient.doRequest( 'delete', @@ -511,6 +577,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{folderId}', Uri.encodeQueryComponent(folderId.toString())); queryParameters['newestItemId'] = newestItemId.toString(); final response = await rootClient.doRequest( @@ -532,6 +603,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -554,6 +630,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['url'] = url; if (folderId != null) { queryParameters['folderId'] = folderId.toString(); @@ -575,6 +656,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{feedId}', Uri.encodeQueryComponent(feedId.toString())); final response = await rootClient.doRequest( 'delete', @@ -596,6 +682,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{feedId}', Uri.encodeQueryComponent(feedId.toString())); if (folderId != null) { queryParameters['folderId'] = folderId.toString(); @@ -620,6 +711,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{feedId}', Uri.encodeQueryComponent(feedId.toString())); queryParameters['feedTitle'] = feedTitle; final response = await rootClient.doRequest( @@ -642,6 +738,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{feedId}', Uri.encodeQueryComponent(feedId.toString())); queryParameters['newestItemId'] = newestItemId.toString(); final response = await rootClient.doRequest( @@ -670,6 +771,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } if (type != 3) { queryParameters['type'] = type.toString(); } @@ -712,6 +818,11 @@ class NextcloudNewsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } if (type != 3) { queryParameters['type'] = type.toString(); } @@ -739,6 +850,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{itemId}', Uri.encodeQueryComponent(itemId.toString())); final response = await rootClient.doRequest( 'post', @@ -757,6 +873,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{itemId}', Uri.encodeQueryComponent(itemId.toString())); final response = await rootClient.doRequest( 'post', @@ -775,6 +896,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{itemId}', Uri.encodeQueryComponent(itemId.toString())); final response = await rootClient.doRequest( 'post', @@ -793,6 +919,11 @@ class NextcloudNewsClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{itemId}', Uri.encodeQueryComponent(itemId.toString())); final response = await rootClient.doRequest( 'post', @@ -826,6 +957,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } if (category != null) { queryParameters['category'] = category; } @@ -871,6 +1007,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } if (category != '') { queryParameters['category'] = category; } @@ -909,6 +1050,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{id}', Uri.encodeQueryComponent(id.toString())); if (exclude != '') { queryParameters['exclude'] = exclude; @@ -943,6 +1089,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{id}', Uri.encodeQueryComponent(id.toString())); if (content != null) { queryParameters['content'] = content; @@ -981,6 +1132,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{id}', Uri.encodeQueryComponent(id.toString())); final response = await rootClient.doRequest( 'delete', @@ -1001,6 +1157,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1020,6 +1181,11 @@ class NextcloudNotesClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } headers['Content-Type'] = 'application/json'; body = Uint8List.fromList(utf8.encode(json.encode(notesSettings.toJson()))); final response = await rootClient.doRequest( @@ -1047,6 +1213,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1067,6 +1238,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'delete', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1086,6 +1262,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{id}', Uri.encodeQueryComponent(id.toString())); final response = await rootClient.doRequest( 'get', @@ -1107,6 +1288,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{id}', Uri.encodeQueryComponent(id.toString())); final response = await rootClient.doRequest( 'delete', @@ -1131,6 +1317,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['pushTokenHash'] = pushTokenHash; queryParameters['devicePublicKey'] = devicePublicKey; queryParameters['proxyServer'] = proxyServer; @@ -1154,6 +1345,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'delete', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1177,6 +1373,11 @@ class NextcloudNotificationsClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{userId}', Uri.encodeQueryComponent(userId)); queryParameters['shortMessage'] = shortMessage; if (longMessage != '') { @@ -1207,6 +1408,11 @@ class NextcloudProvisioningApiClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1227,6 +1433,11 @@ class NextcloudProvisioningApiClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{userId}', Uri.encodeQueryComponent(userId)); final response = await rootClient.doRequest( 'get', @@ -1255,6 +1466,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1279,6 +1495,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['keepalive'] = keepalive.toString(); final response = await rootClient.doRequest( 'put', @@ -1302,6 +1523,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['deviceName'] = deviceName; final response = await rootClient.doRequest( 'put', @@ -1327,6 +1553,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{deviceId}', Uri.encodeQueryComponent(deviceId)); final response = await rootClient.doRequest( 'get', @@ -1350,6 +1581,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{deviceId}', Uri.encodeQueryComponent(deviceId)); final response = await rootClient.doRequest( 'delete', @@ -1375,6 +1611,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['deviceId'] = deviceId; queryParameters['appName'] = appName; final response = await rootClient.doRequest( @@ -1398,6 +1639,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{token}', Uri.encodeQueryComponent(token)); final response = await rootClient.doRequest( 'delete', @@ -1421,6 +1667,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{token}', Uri.encodeQueryComponent(token)); final response = await rootClient.doRequest( 'get', @@ -1443,6 +1694,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{token}', Uri.encodeQueryComponent(token)); final response = await rootClient.doRequest( 'post', @@ -1465,6 +1721,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1486,6 +1747,11 @@ class NextcloudUnifiedPushProviderClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'post', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1512,6 +1778,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1532,6 +1803,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } path = path.replaceAll('{userId}', Uri.encodeQueryComponent(userId)); final response = await rootClient.doRequest( 'get', @@ -1553,6 +1829,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1573,6 +1854,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['statusType'] = statusType.value; final response = await rootClient.doRequest( 'put', @@ -1597,6 +1883,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['messageId'] = messageId; if (clearAt != null) { queryParameters['clearAt'] = clearAt.toString(); @@ -1625,6 +1916,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } if (statusIcon != null) { queryParameters['statusIcon'] = statusIcon; } @@ -1652,6 +1948,11 @@ class NextcloudUserStatusClient { final queryParameters = {}; final headers = {}; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'delete', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1671,6 +1972,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } final response = await rootClient.doRequest( 'get', Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null).toString(), @@ -1691,6 +1997,11 @@ class NextcloudUserStatusClient { 'Accept': 'application/json', }; Uint8List? body; + if (rootClient.authentications.map((final a) => a.id).contains('basic_auth')) { + headers.addAll(rootClient.authentications.singleWhere((final a) => a.id == 'basic_auth').headers); + } else { + throw Exception('Missing authentication for basic_auth'); + } queryParameters['status'] = status.value; final response = await rootClient.doRequest( 'put', diff --git a/packages/nextcloud/lib/src/nextcloud.openapi.json b/packages/nextcloud/lib/src/nextcloud.openapi.json index fd322a15..649a8b69 100644 --- a/packages/nextcloud/lib/src/nextcloud.openapi.json +++ b/packages/nextcloud/lib/src/nextcloud.openapi.json @@ -2008,6 +2008,7 @@ "tags": [ "core" ], + "security": [], "responses": { "200": { "description": "Status of the Nextcloud instance", diff --git a/packages/nextcloud/lib/src/webdav/client.dart b/packages/nextcloud/lib/src/webdav/client.dart index 05d6f01c..35f248fb 100644 --- a/packages/nextcloud/lib/src/webdav/client.dart +++ b/packages/nextcloud/lib/src/webdav/client.dart @@ -43,6 +43,7 @@ class WebDavClient { HttpHeaders.contentTypeHeader: 'application/xml', ...rootClient.baseHeaders, if (headers != null) ...headers, + if (rootClient.authentications.isNotEmpty) ...rootClient.authentications.first.headers, }.entries) { request.headers.add(header.key, header.value); } diff --git a/specs/core.json b/specs/core.json index 2fbd36a4..906bd141 100644 --- a/specs/core.json +++ b/specs/core.json @@ -982,6 +982,7 @@ "tags": [ "core" ], + "security": [], "responses": { "200": { "description": "Status of the Nextcloud instance",