2019-12-29 10:28:33 +00:00
|
|
|
/*
|
2020-06-03 10:16:01 +00:00
|
|
|
* Famedly Matrix SDK
|
|
|
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
2019-12-29 10:28:33 +00:00
|
|
|
*
|
2020-06-03 10:16:01 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
2019-12-29 10:28:33 +00:00
|
|
|
*
|
2020-06-03 10:16:01 +00:00
|
|
|
* 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.
|
2019-12-29 10:28:33 +00:00
|
|
|
*
|
2020-06-03 10:16:01 +00:00
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-12-29 10:28:33 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
|
|
|
|
enum MatrixError {
|
|
|
|
M_UNKNOWN,
|
|
|
|
M_UNKNOWN_TOKEN,
|
|
|
|
M_NOT_FOUND,
|
|
|
|
M_FORBIDDEN,
|
|
|
|
M_LIMIT_EXCEEDED,
|
|
|
|
M_USER_IN_USE,
|
|
|
|
M_THREEPID_IN_USE,
|
|
|
|
M_THREEPID_DENIED,
|
|
|
|
M_THREEPID_NOT_FOUND,
|
|
|
|
M_THREEPID_AUTH_FAILED,
|
|
|
|
M_TOO_LARGE,
|
|
|
|
M_MISSING_PARAM,
|
|
|
|
M_UNSUPPORTED_ROOM_VERSION,
|
|
|
|
M_UNRECOGNIZED,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents a special response from the Homeserver for errors.
|
|
|
|
class MatrixException implements Exception {
|
|
|
|
final Map<String, dynamic> raw;
|
|
|
|
|
|
|
|
/// The unique identifier for this error.
|
2020-01-14 11:27:26 +00:00
|
|
|
String get errcode =>
|
2020-03-30 09:08:38 +00:00
|
|
|
raw['errcode'] ??
|
|
|
|
(requireAdditionalAuthentication ? 'M_FORBIDDEN' : 'M_UNKNOWN');
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// A human readable error description.
|
2020-01-14 11:27:26 +00:00
|
|
|
String get errorMessage =>
|
2020-03-30 09:08:38 +00:00
|
|
|
raw['error'] ??
|
2020-01-14 11:27:26 +00:00
|
|
|
(requireAdditionalAuthentication
|
2020-03-30 09:08:38 +00:00
|
|
|
? 'Require additional authentication'
|
|
|
|
: 'Unknown error');
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// The frozen request which triggered this Error
|
|
|
|
http.Response response;
|
|
|
|
|
2020-03-30 09:08:38 +00:00
|
|
|
MatrixException(this.response) : raw = json.decode(response.body);
|
2020-06-03 10:16:01 +00:00
|
|
|
MatrixException.fromJson(Map<String, dynamic> content) : raw = content;
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
@override
|
2020-03-30 09:08:38 +00:00
|
|
|
String toString() => '$errcode: $errorMessage';
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// Returns the [ResponseError]. Is ResponseError.NONE if there wasn't an error.
|
|
|
|
MatrixError get error => MatrixError.values.firstWhere(
|
|
|
|
(e) => e.toString() == 'MatrixError.${(raw["errcode"] ?? "")}',
|
|
|
|
orElse: () => MatrixError.M_UNKNOWN);
|
|
|
|
|
2020-03-30 09:08:38 +00:00
|
|
|
int get retryAfterMs => raw['retry_after_ms'];
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// This is a session identifier that the client must pass back to the homeserver, if one is provided,
|
|
|
|
/// in subsequent attempts to authenticate in the same API call.
|
2020-03-30 09:08:38 +00:00
|
|
|
String get session => raw['session'];
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// Returns true if the server requires additional authentication.
|
2020-06-03 10:16:01 +00:00
|
|
|
bool get requireAdditionalAuthentication => response != null
|
|
|
|
? response.statusCode == 401
|
|
|
|
: authenticationFlows != null;
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// For each endpoint, a server offers one or more 'flows' that the client can use
|
|
|
|
/// to authenticate itself. Each flow comprises a series of stages. If this request
|
|
|
|
/// doesn't need additional authentication, then this is null.
|
|
|
|
List<AuthenticationFlow> get authenticationFlows {
|
2020-03-30 09:08:38 +00:00
|
|
|
if (!raw.containsKey('flows') || !(raw['flows'] is List)) return null;
|
|
|
|
var flows = <AuthenticationFlow>[];
|
|
|
|
for (Map<String, dynamic> flow in raw['flows']) {
|
|
|
|
if (flow['stages'] is List) {
|
|
|
|
flows.add(AuthenticationFlow(List<String>.from(flow['stages'])));
|
2019-12-29 10:28:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return flows;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This section contains any information that the client will need to know in order to use a given type
|
|
|
|
/// of authentication. For each authentication type presented, that type may be present as a key in this
|
|
|
|
/// dictionary. For example, the public part of an OAuth client ID could be given here.
|
2020-03-30 09:08:38 +00:00
|
|
|
Map<String, dynamic> get authenticationParams => raw['params'];
|
2019-12-29 10:28:33 +00:00
|
|
|
|
|
|
|
/// Returns the list of already completed authentication flows from previous requests.
|
2020-03-30 09:08:38 +00:00
|
|
|
List<String> get completedAuthenticationFlows =>
|
|
|
|
List<String>.from(raw['completed'] ?? []);
|
2019-12-29 10:28:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// For each endpoint, a server offers one or more 'flows' that the client can use
|
|
|
|
/// to authenticate itself. Each flow comprises a series of stages
|
|
|
|
class AuthenticationFlow {
|
|
|
|
final List<String> stages;
|
|
|
|
const AuthenticationFlow(this.stages);
|
|
|
|
}
|