Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. import * as Keychain from 'react-native-keychain';
  20. import { REQUEST_STATUS } from '../utils/Requests';
  21. import type { ApiDataLoginType, ApiRejectType } from '../utils/WebData';
  22. import { apiRequest } 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 AUTH_PATH = 'password';
  34. export default class ConnectionManager {
  35. static instance: ConnectionManager | null = null;
  36. private token: string | null;
  37. constructor() {
  38. this.token = null;
  39. }
  40. /**
  41. * Gets this class instance or create one if none is found
  42. *
  43. * @returns {ConnectionManager}
  44. */
  45. static getInstance(): ConnectionManager {
  46. if (ConnectionManager.instance == null) {
  47. ConnectionManager.instance = new ConnectionManager();
  48. }
  49. return ConnectionManager.instance;
  50. }
  51. /**
  52. * Gets the current token
  53. *
  54. * @returns {string | null}
  55. */
  56. getToken(): string | null {
  57. return this.token;
  58. }
  59. /**
  60. * Tries to recover login token from the secure keychain
  61. *
  62. * @returns Promise<void>
  63. */
  64. async recoverLogin(): Promise<void> {
  65. return new Promise((resolve: () => void) => {
  66. const token = this.getToken();
  67. if (token != null) {
  68. resolve();
  69. } else {
  70. Keychain.getGenericPassword()
  71. .then((data: Keychain.UserCredentials | false) => {
  72. if (data && data.password != null) {
  73. this.token = data.password;
  74. }
  75. resolve();
  76. })
  77. .catch(() => resolve());
  78. }
  79. });
  80. }
  81. /**
  82. * Check if the user has a valid token
  83. *
  84. * @returns {boolean}
  85. */
  86. isLoggedIn(): boolean {
  87. return this.getToken() !== null;
  88. }
  89. /**
  90. * Saves the login token in the secure keychain
  91. *
  92. * @param email
  93. * @param token
  94. * @returns Promise<void>
  95. */
  96. async saveLogin(_email: string, token: string): Promise<void> {
  97. return new Promise((resolve: () => void, reject: () => void) => {
  98. Keychain.setGenericPassword('token', token)
  99. .then(() => {
  100. this.token = token;
  101. resolve();
  102. })
  103. .catch((): void => reject());
  104. });
  105. }
  106. /**
  107. * Deletes the login token from the keychain
  108. *
  109. * @returns Promise<void>
  110. */
  111. async disconnect(): Promise<void> {
  112. return new Promise((resolve: () => void, reject: () => void) => {
  113. Keychain.resetGenericPassword()
  114. .then(() => {
  115. this.token = null;
  116. resolve();
  117. })
  118. .catch((): void => reject());
  119. });
  120. }
  121. /**
  122. * Sends the given login and password to the api.
  123. * If the combination is valid, the login token is received and saved in the secure keychain.
  124. * If not, the promise is rejected with the corresponding error code.
  125. *
  126. * @param email
  127. * @param password
  128. * @returns Promise<void>
  129. */
  130. async connect(email: string, password: string): Promise<void> {
  131. return new Promise(
  132. (resolve: () => void, reject: (error: ApiRejectType) => void) => {
  133. const data = {
  134. email,
  135. password,
  136. };
  137. apiRequest<ApiDataLoginType>(AUTH_PATH, 'POST', data)
  138. .then((response: ApiDataLoginType) => {
  139. if (response.token != null) {
  140. this.saveLogin(email, response.token)
  141. .then(() => resolve())
  142. .catch(() =>
  143. reject({
  144. status: REQUEST_STATUS.TOKEN_SAVE,
  145. })
  146. );
  147. } else {
  148. reject({
  149. status: REQUEST_STATUS.SERVER_ERROR,
  150. });
  151. }
  152. })
  153. .catch((err) => {
  154. reject(err);
  155. });
  156. }
  157. );
  158. }
  159. /**
  160. * Sends an authenticated request with the login token to the API
  161. *
  162. * @param path
  163. * @param params
  164. * @returns Promise<ApiGenericDataType>
  165. */
  166. async authenticatedRequest<T>(
  167. path: string,
  168. params?: { [key: string]: any }
  169. ): Promise<T> {
  170. return new Promise(
  171. (
  172. resolve: (response: T) => void,
  173. reject: (error: ApiRejectType) => void
  174. ) => {
  175. if (this.getToken() !== null) {
  176. const data = {
  177. ...params,
  178. token: this.getToken(),
  179. };
  180. apiRequest<T>(path, 'POST', data)
  181. .then((response: T) => resolve(response))
  182. .catch(reject);
  183. } else {
  184. reject({
  185. status: REQUEST_STATUS.TOKEN_RETRIEVE,
  186. });
  187. }
  188. }
  189. );
  190. }
  191. }