/* * 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); }