Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ConnectionManager.ts 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. // @flow
  20. import * as Keychain from 'react-native-keychain';
  21. import type {ApiDataLoginType} from '../utils/WebData';
  22. import {apiRequest, ERROR_TYPE} from '../utils/WebData';
  23. /**
  24. * champ: error
  25. *
  26. * 0 : SUCCESS -> pas d'erreurs
  27. * 1 : BAD_CREDENTIALS -> email ou mdp invalide
  28. * 2 : BAD_TOKEN -> session expirée
  29. * 3 : NO_CONSENT
  30. * 403 : FORBIDDEN -> accès a la ressource interdit
  31. * 500 : SERVER_ERROR -> pb coté serveur
  32. */
  33. const SERVER_NAME = 'amicale-insat.fr';
  34. const AUTH_PATH = 'password';
  35. export default class ConnectionManager {
  36. static instance: ConnectionManager | null = null;
  37. private token: string | null;
  38. constructor() {
  39. this.token = null;
  40. }
  41. /**
  42. * Gets this class instance or create one if none is found
  43. *
  44. * @returns {ConnectionManager}
  45. */
  46. static getInstance(): ConnectionManager {
  47. if (ConnectionManager.instance == null) {
  48. ConnectionManager.instance = new ConnectionManager();
  49. }
  50. return ConnectionManager.instance;
  51. }
  52. /**
  53. * Gets the current token
  54. *
  55. * @returns {string | null}
  56. */
  57. getToken(): string | null {
  58. return this.token;
  59. }
  60. /**
  61. * Tries to recover login token from the secure keychain
  62. *
  63. * @returns Promise<string>
  64. */
  65. async recoverLogin(): Promise<string> {
  66. return new Promise(
  67. (resolve: (token: string) => void, reject: () => void) => {
  68. const token = this.getToken();
  69. if (token != null) {
  70. resolve(token);
  71. } else {
  72. Keychain.getInternetCredentials(SERVER_NAME)
  73. .then((data: Keychain.UserCredentials | false) => {
  74. if (data && data.password != null) {
  75. this.token = data.password;
  76. resolve(this.token);
  77. } else {
  78. reject();
  79. }
  80. })
  81. .catch((): void => reject());
  82. }
  83. },
  84. );
  85. }
  86. /**
  87. * Check if the user has a valid token
  88. *
  89. * @returns {boolean}
  90. */
  91. isLoggedIn(): boolean {
  92. return this.getToken() !== null;
  93. }
  94. /**
  95. * Saves the login token in the secure keychain
  96. *
  97. * @param email
  98. * @param token
  99. * @returns Promise<void>
  100. */
  101. async saveLogin(email: string, token: string): Promise<void> {
  102. return new Promise((resolve: () => void, reject: () => void) => {
  103. Keychain.setInternetCredentials(SERVER_NAME, 'token', token)
  104. .then(() => {
  105. this.token = token;
  106. resolve();
  107. })
  108. .catch((): void => reject());
  109. });
  110. }
  111. /**
  112. * Deletes the login token from the keychain
  113. *
  114. * @returns Promise<void>
  115. */
  116. async disconnect(): Promise<void> {
  117. return new Promise((resolve: () => void, reject: () => void) => {
  118. Keychain.resetInternetCredentials(SERVER_NAME)
  119. .then(() => {
  120. this.token = null;
  121. resolve();
  122. })
  123. .catch((): void => reject());
  124. });
  125. }
  126. /**
  127. * Sends the given login and password to the api.
  128. * If the combination is valid, the login token is received and saved in the secure keychain.
  129. * If not, the promise is rejected with the corresponding error code.
  130. *
  131. * @param email
  132. * @param password
  133. * @returns Promise<void>
  134. */
  135. async connect(email: string, password: string): Promise<void> {
  136. return new Promise(
  137. (resolve: () => void, reject: (error: number) => void) => {
  138. const data = {
  139. email,
  140. password,
  141. };
  142. apiRequest<ApiDataLoginType>(AUTH_PATH, 'POST', data)
  143. .then((response: ApiDataLoginType) => {
  144. if (response.token != null) {
  145. this.saveLogin(email, response.token)
  146. .then((): void => resolve())
  147. .catch((): void => reject(ERROR_TYPE.TOKEN_SAVE));
  148. } else {
  149. reject(ERROR_TYPE.SERVER_ERROR);
  150. }
  151. })
  152. .catch((error: number): void => reject(error));
  153. },
  154. );
  155. }
  156. /**
  157. * Sends an authenticated request with the login token to the API
  158. *
  159. * @param path
  160. * @param params
  161. * @returns Promise<ApiGenericDataType>
  162. */
  163. async authenticatedRequest<T>(
  164. path: string,
  165. params: {[key: string]: any},
  166. ): Promise<T> {
  167. return new Promise(
  168. (resolve: (response: T) => void, reject: (error: number) => void) => {
  169. if (this.getToken() !== null) {
  170. const data = {
  171. ...params,
  172. token: this.getToken(),
  173. };
  174. apiRequest<T>(path, 'POST', data)
  175. .then((response: T): void => resolve(response))
  176. .catch((error: number): void => reject(error));
  177. } else {
  178. reject(ERROR_TYPE.TOKEN_RETRIEVE);
  179. }
  180. },
  181. );
  182. }
  183. }