/*
* Famedly Matrix SDK
* Copyright (C) 2019, 2020 Famedly GmbH
*
* 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.
*
* 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
* along with this program. If not, see .
*/
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 raw;
/// The unique identifier for this error.
String get errcode =>
raw['errcode'] ??
(requireAdditionalAuthentication ? 'M_FORBIDDEN' : 'M_UNKNOWN');
/// A human readable error description.
String get errorMessage =>
raw['error'] ??
(requireAdditionalAuthentication
? 'Require additional authentication'
: 'Unknown error');
/// The frozen request which triggered this Error
http.Response response;
MatrixException(this.response) : raw = json.decode(response.body);
MatrixException.fromJson(Map content) : raw = content;
@override
String toString() => '$errcode: $errorMessage';
/// 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);
int get retryAfterMs => raw['retry_after_ms'];
/// 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.
String get session => raw['session'];
/// Returns true if the server requires additional authentication.
bool get requireAdditionalAuthentication => response != null
? response.statusCode == 401
: authenticationFlows != null;
/// 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 get authenticationFlows {
if (!raw.containsKey('flows') || !(raw['flows'] is List)) return null;
var flows = [];
for (Map flow in raw['flows']) {
if (flow['stages'] is List) {
flows.add(AuthenticationFlow(List.from(flow['stages'])));
}
}
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.
Map get authenticationParams => raw['params'];
/// Returns the list of already completed authentication flows from previous requests.
List get completedAuthenticationFlows =>
List.from(raw['completed'] ?? []);
}
/// 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 stages;
const AuthenticationFlow(this.stages);
}