Stop multiple request sent on refresh token using axios-auth-refresh - javascript

I am using axios-auth-refresh axios interceptor 3rd party library to handle my refresh token, the issue is that i have multiple request on my dashboard around 10 request and every time when the token expires, it will execute the my refresh token function multiple times and based on how many requests that are made. I previously refer to this stackoverflow question but it didn't somehow work on me and some requests are not being made then I opt at using axios-auth-refresh library to handle my refresh token function, because I thought that the option pauseInstanceWhileRefreshing: true will help me prevent it but it didn't somehow work.
What I want to achieve is to execute a single refresh token request to the server while other requests are on queue (I am using cookie to store my token), once it successfully replace the token then it will retry or resend those request back to the server. Below is my code:
import axios from 'axios';
import axiosRetry from 'axios-retry';
import config from 'config';
import {isNull, isUndefined} from 'underscore';
import Cookies from 'universal-cookie';
import createAuthRefreshInterceptor from 'axios-auth-refresh';
const api_client = () => {
const client = axios.create({baseURL: config.server});
const cookies = new Cookies();
client.interceptors.request.use(request => {
const cookies = new Cookies();
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if(!isNull(cookieToken) && !isNull(cookieUser)) {
if(!isUndefined(cookieToken.token)) {
request.headers['Authorization'] = `Bearer ${cookieToken.token}`;
}
request.withCredentials = true;
request.headers['Content-Type'] = 'application/json'
request.headers['X-Fname'] = cookieUser.username;
}
return request;
}, error => {
console.log(error);
});
const handleRefreshAuth = failedRequest => {
return getRefreshAuthToken().then(response => {
if(response.data) {
cookies.remove("token", { domain: window.location.hostname, path: "/grt" });
cookies.remove("token", { domain: window.location.hostname, path: "/" });
cookies.set("token", { token: response.data.token, refreshToken: response.data.refreshToken, }, { domain: window.location.hostname, path: "/grt", expires: new Date(Date.now() + 259200) });
failedRequest.response.config.headers['Authorization'] = `Bearer ${response.data.token}`;
return Promise.resolve();
}
})
}
const options = {
pauseInstanceWhileRefreshing: true
}
createAuthRefreshInterceptor(client, handleRefreshAuth, options);
const getRefreshAuthToken = () => {
return new Promise((resolve, reject) => {
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if((!isNull(cookieToken) && !isNull(cookieUser)) || (!isUndefined(cookieToken) && !isUndefined(cookieUser))) {
client.post(`/user/refresh?refreshToken=${cookieToken.refreshToken}`).then(response => {
if(response) {
resolve(response)
}
})
}
})
}
return client;
}
export const retrieve = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().get(url, data).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export const send = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().post(url, data, { skipAuthRefresh: true }).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export default {retrieve, send};
Network
Old code
I added this one as well, it might be that I missed something else on this one, using raw axios interceptor method, same issue as the new one.
import axios from 'axios';
import axiosRetry from 'axios-retry';
import config from 'config';
import {isNull, isUndefined} from 'underscore';
import Cookies from 'universal-cookie';
const api_client = () => {
const client = axios.create({baseURL: config.server});
let isRefreshing = false;
let failedQueue = [];
const retryCodes = [
401
]
axiosRetry(client, {
retries: 3,
retryDelay: (retryCount) => {
return retryCount * 1000;
},
retryCondition: (error) => {
return retryCodes.includes(error.response.status);
}
});
client.interceptors.request.use(request => {
const cookies = new Cookies();
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if(!isNull(cookieToken) && !isNull(cookieUser)) {
if(!isUndefined(cookieToken.token)) {
request.headers['Authorization'] = `Bearer ${cookieToken.token}`;
}
request.withCredentials = true;
request.headers['Content-Type'] = 'application/json'
request.headers['X-Fname'] = cookieUser.username;
}
return request;
}, error => {
console.log(error);
});
const processQueue = (error, token = null) => {
const cookies = new Cookies();
console.log('processQueue', token)
failedQueue.forEach(prom => {
if (error) {
prom.reject(error);
} else {
const cookieToken = cookies.get('token');
prom.resolve(cookieToken.token);
}
})
failedQueue = [];
}
const getRefreshAuthToken = async () => {
return new Promise(async (resolve, reject) => {
const cookies = new Cookies();
const cookieToken = cookies.get('token');
const cookieUser = cookies.get('user');
if((!isNull(cookieToken) && !isNull(cookieUser)) || (!isUndefined(cookieToken) && !isUndefined(cookieUser))) {
await client.post(`/user/refresh?refreshToken=${cookieToken.refreshToken}`).then(response => {
if(response) {
resolve(response)
}
})
}
})
}
client.interceptors.response.use(response => {
return response;
}, error => {
const originalRequest = error.config;
const cookies = new Cookies();
if (error.response.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise(function(resolve, reject) {
failedQueue.push({ resolve, reject });
}).then(response => {
if(response) {
console.log('from test response', response)
cookies.remove("token", { domain: window.location.hostname, path: "/grt" });
cookies.remove("token", { domain: window.location.hostname, path: "/" });
cookies.set("token", { token: response.data.token, refreshToken: response.data.refreshToken, }, { domain: window.location.hostname, path: "/grt", expires: new Date(Date.now() + 259200) });
originalRequest.headers['Authorization'] = `Bearer ${cookies.get('token').token}`;
return client(originalRequest);
}
}).catch(error => {
return Promise.reject(error);
});
}
originalRequest._retry = true;
isRefreshing = true;
return new Promise((resolve, reject) => {
getRefreshAuthToken()
.then(response => {
if(!isUndefined(response)) {
cookies.remove("token", { domain: window.location.hostname, path: "/grt" });
cookies.remove("token", { domain: window.location.hostname, path: "/" });
cookies.set("token", { token: response.data.token, refreshToken: response.data.refreshToken, }, { domain: window.location.hostname, path: "/grt", expires: new Date(Date.now() + 259200) });
}
processQueue(null, cookies.get('token').token);
resolve(client(originalRequest));
}).catch(error => {
// add to queue for failed requests
processQueue(error, null);
reject(error);
}).then(() => {
isRefreshing = false
});
});
}
return Promise.reject(error);
})
return client;
}
export const retrieve = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().get(url, data).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export const send = async (url, data = undefined) => {
return new Promise(async (resolve, reject) => {
await api_client().post(url, data, { skipAuthRefresh: true }).then(response => {
if(response) {
resolve(response.data);
}
})
})
}
export default {retrieve, send};
Does anyone knows how to fix this? If so, please let me know, thanks!

Related

How to use authenticated proxies with undici

Hello so am trying to use undici with a proxy but it doesn't work i tired this
const client = new Client({
url: 'www.google.com',
proxy: 'http://user:pass#host:port'
})
as well as this
const { HttpsProxyAgent } = require("https-proxy-agent");
const proxy = new HttpsProxyAgent("http://user:pass#host:port");
time = new Date()
client.request({
path: '/',
method: 'GET',
httpsAgent: proxy
},
but nothing seems to work
See this link here:
https://github.com/nodejs/undici/blob/01302e6d2b2629cca4ad9327abe0f7a317f8399f/docs/best-practices/proxy.md#connect-with-authentication
import { Client } from 'undici'
import { createServer } from 'http'
import proxy from 'proxy'
const server = await buildServer()
const proxy = await buildProxy()
const serverUrl = `http://localhost:${server.address().port}`
const proxyUrl = `http://localhost:${proxy.address().port}`
proxy.authenticate = function (req, fn) {
fn(null, req.headers['proxy-authorization'] === `Basic ${Buffer.from('user:pass').toString('base64')}`)
}
server.on('request', (req, res) => {
console.log(req.url) // '/hello?foo=bar'
res.setHeader('content-type', 'application/json')
res.end(JSON.stringify({ hello: 'world' }))
})
const client = new Client(proxyUrl)
const response = await client.request({
method: 'GET',
path: serverUrl + '/hello?foo=bar',
headers: {
'proxy-authorization': `Basic ${Buffer.from('user:pass').toString('base64')}`
}
})
response.body.setEncoding('utf8')
let data = ''
for await (const chunk of response.body) {
data += chunk
}
console.log(response.statusCode) // 200
console.log(JSON.parse(data)) // { hello: 'world' }
server.close()
proxy.close()
client.close()
function buildServer () {
return new Promise((resolve, reject) => {
const server = createServer()
server.listen(0, () => resolve(server))
})
}
function buildProxy () {
return new Promise((resolve, reject) => {
const server = proxy(createServer())
server.listen(0, () => resolve(server))
})
}

Way to handle refresh token

I am working on login feature and have problem when refresh token.
When token expire making request to refresh token, remove the old token, and save the new token to AsyncStorage.
After login successfully have to function A and B. The function A is using the new token to make its request. the function B say that it need to refresh the token so make request to refresh token ( the request make successfully, token being refresh) but The token that request A is using now invalid - I think it happens due to asynchronous
This is my code that use to refresh token:
axiosInstance.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
if (error.response.status === CODE_TOKEN_EXPIRED) {
try {
const token = await authenticationService.getRefreshToken();
const response = await authenticationService.refreshToken(token);
await authenticationService.removeToken();
await authenticationService.storeToken(response.data.params.access_token);
await authenticationService.storeRefreshToken(response.data.params.refresh_token);
error.config.headers.Authorization = 'Bearer ' + response.data.params.access_token;
error.response.config.headers['Authorization'] = 'Bearer ' + response.data.params.access_token;
return axiosInstance(error.config);
} catch (err) {
console.log(2, err);
await authenticationService.removeToken();
navigationService.navigate('LoginForm');
}
}
return Promise.reject(error);
}
);
Anyone know how to handle which asynchronous call for refresh token?
First would be for you to check if you are changing token to the correct axios instance. It is necessary to change Authorization header on error.response config as you did, but also for main axios instance (if you have one) like so: axios.defaults.headers.common["Authorization"] = "Bearer " + access_token;
If it is multiple parallel requests going on that could possibly need to be postponed after token is refreshed issue and answer gets complex, but check this gist with full refresh logic with axios.
I have implemented the same scenario in fetch API. you can also do this same in axios API. Try this to avoid interceptor concept.
Api.ts
export const api = ({ method, url, body, isProtected = true }) => {
return new Promise((resolve, reject) => {
const payload = {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
};
if (body !== null) {
(payload as any).body = JSON.stringify(body);
}
/**
* "isProtected" is used for API call without authToken
*/
if (isProtected) {
AsyncStorage.getItem(ACCESS_TOKEN).then(accessKey => {
(payload.headers as any).Authorization = `Bearer ${accessKey}`;
fetch(url, payload)
.then((response: any) => {
/*
* 419 status denotes the timeout of authToken
*/
if (response.status == 419) {
// refresh token
AsyncStorage.getItem(REFRESH_TOKEN).then(refreshKey => {
const payloadRef = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + refreshKey
}
};
/*
* This call refresh the authToken using refreshing call to renew the authToken
*/
fetch(URL.baseUrl + "/refresh", payloadRef)
.then((response: any) => response.json())
.then(response => {
/*
* if refresh token expired. redirect to login page
*/
if (response.status !== codes.SUCCESS) {
if (!User.sessionOver) {
User.sessionOver = true;
Alert.alert(
'Alert',
'Session Timeout',
[
{
text: 'Get back to Login',
onPress: () => {
// get to Login page
}
}
],
{ cancelable: false }
);
}
} else if (response.status == codes.SUCCESS) {
/*
* If refresh token got refreshed and set it as authToken and retry the api call.
*/
AsyncStorage.setItem(ACCESS_TOKEN, response.payload.access_key).then(() => {
(payload.headers as any).Authorization = 'Bearer ' + response.payload.access_key;
fetch(url, payload)
.then(response => response.json())
.then(response => {
if (response.status == codes.SUCCESS) {
resolve(response);
}
})
.catch(error => {
reject(error);
});
});
}
});
});
} else {
resolve(response.json());
}
})
.catch(error => {
reject(error);
});
});
} else {
fetch(url, payload)
.then((response: any) => {
response = response.json();
resolve(response);
})
.catch(error => {
reject(error);
});
}
});
};
MovieService.ts
import { api } from '../services/api';
import { URL } from '../config/UrlConfig';
const getMovies = () => {
const method = 'GET';
const url = URL.baseUrl + '/v1/top/movies';
const body = null;
const isProtected = true;
return api({ method, url, body, isProtected });
};
export { getMovies };
Maybe it will helps - https://gist.github.com/ModPhoenix/f1070f1696faeae52edf6ee616d0c1eb
import axios from "axios";
import { settings } from "../settings";
import { authAPI } from ".";
const request = axios.create({
baseURL: settings.apiV1,
});
request.interceptors.request.use(
(config) => {
// Get token and add it to header "Authorization"
const token = authAPI.getAccessToken();
if (token) {
config.headers.Authorization = token;
}
return config;
},
(error) => Promise.reject(error)
);
let loop = 0;
let isRefreshing = false;
let subscribers = [];
function subscribeTokenRefresh(cb) {
subscribers.push(cb);
}
function onRrefreshed(token) {
subscribers.map((cb) => cb(token));
}
request.interceptors.response.use(undefined, (err) => {
const {
config,
response: { status },
} = err;
const originalRequest = config;
if (status === 401 && loop < 1) {
loop++;
if (!isRefreshing) {
isRefreshing = true;
authAPI.refreshToken().then((respaonse) => {
const { data } = respaonse;
isRefreshing = false;
onRrefreshed(data.access_token);
authAPI.setAccessToken(data.access_token);
authAPI.setRefreshToken(data.refresh_token);
subscribers = [];
});
}
return new Promise((resolve) => {
subscribeTokenRefresh((token) => {
originalRequest.headers.Authorization = `Bearer ${token}`;
resolve(axios(originalRequest));
});
});
}
return Promise.reject(err);
});
export default request;

"Converting circular structure to JSON" error despite functions being executed properly

I'm getting the following error:
TypeError: Converting circular structure to JSON
at JSON.stringify (<anonymous>)
at stringify (/usr/local/lib/node_modules/firebase-tools/node_modules/express/lib/response.js:1123:12)
at ServerResponse.json (/usr/local/lib/node_modules/firebase-tools/node_modules/express/lib/response.js:260:14)
at cors (/Users/landing-page-backend/functions/zohoCrmHook.js:45:43)
at process._tickCallback (internal/process/next_tick.js:68:7)
for the HTTP response in my createLead function, despite the fact that the function is executed properly and does what it's supposed to do (which is to create an entry in my CRM).
I've pointed out in the following code where the error occurs:
const axios = require('axios');
const functions = require('firebase-functions');
const cors = require('cors')({ origin: true })
const clientId = functions.config().zoho.client_id;
const clientSecret = functions.config().zoho.client_secret;
const refreshToken = functions.config().zoho.refresh_token;
const baseURL = 'https://accounts.zoho.com';
module.exports = (req, res) => {
cors(req, res, async () => {
const newLead = {
'data': [
{
'Email': String(req.body.email),
'Last_Name': String(req.body.lastName),
'First_Name': String(req.body.firstName),
}
],
'trigger': [
'approval',
'workflow',
'blueprint'
]
};
const { data } = await getAccessToken();
const accessToken = data.access_token;
const leads = await getLeads(accessToken);
const result = checkLeads(leads.data.data, newLead.data[0].Email);
if (result.length < 1) {
try {
return res.json(await createLead(accessToken, newLead)); // this is where the error occurs
} catch (e) {
console.log(e);
}
} else {
return res.json({ message: 'Lead already in CRM' })
}
})
}
function getAccessToken () {
const url = `https://accounts.zoho.com/oauth/v2/token?refresh_token=${refreshToken}&client_id=${clientId}&client_secret=${clientSecret}&grant_type=refresh_token`;
return new Promise((resolve, reject) => {
axios.post(url)
.then((response) => {
return resolve(response);
})
.catch(e => console.log("getAccessToken error", e))
});
}
function getLeads(token) {
const url = 'https://www.zohoapis.com/crm/v2/Leads';
return new Promise((resolve, reject) => {
axios.get(url, {
headers: {
'Authorization': `Zoho-oauthtoken ${token}`
}
})
.then((response) => {
return resolve(response);
})
.catch(e => console.log("getLeads error", e))
})
}
function createLead(token, lead) {
const url = 'https://www.zohoapis.com/crm/v2/Leads';
return new Promise((resolve, reject) => {
const data = JSON.stringify(lead);
axios.post(url, data, {
headers: {
'Authorization': `Zoho-oauthtoken ${token}`
}
})
.then((response) => {
console.log("response in createLead", response)
return resolve(response);
})
.catch(e => reject(e))
})
}
function checkLeads(leads, currentLead) {
return leads.filter(lead => lead.Email === currentLead)
}
Console.logging all the parameters indicate that the they are not the issue. The configuration of the Zoho API is, also, not the issue considering the fact that the entries are being properly made into the CRM. My assumption is that it would have to do with the HTTP response in the JSON format.
You're trying to convert a promise to JSON, not going to work. Your createLead function returns a promise, not a JSON. The promise is the 'circular object'.

Axios interceptor refresh token for multiple requests

I'll throw the http request because I'm calling the refresh token when it returns 401. After the refresh token response, I need to throw the previous request
SAMPLE
Logın -> — 1 hours later— —> call product —> 401 —> call refresh token —> call product
I try this link a link and look this link a link but doesn't work.
Catch the 401 error
setInterceptors = () => {
axios.interceptors.response.use(
response => {
return response;
},
err => {
return new Promise((resolve, reject) => {
if (err.response.status === 401 && err.config && !err.config.__isRetryRequest) {
const originalRequest = err.config;
this.emit('onAutoLogin', originalRequest);
}
// throw err;
});
}
);
};
Call my action
jwtService.on('onAutoLogin', originalRequest => {
jwtService
.signInWithToken()
.then(res => {
if (res.access_token) {
originalRequest.headers['Authorization'] = 'Bearer ' + res.access_token;
Axios.request(originalRequest).then(response => {
store.dispatch({
type: ** MY PROBLEM İS HERE **
payload: response.data
});
});
}
})
.catch(err => {
jwtService.setSession(null);
});
using this link I was able to solve the problem without triggering the redux store.
let isRefreshing = false;
let failedQueue = [];
const processQueue = (error, token = null) => {
failedQueue.forEach(prom => {
if (error) {
prom.reject(error);
} else {
prom.resolve(token);
}
});
failedQueue = [];
};
axios.interceptors.response.use(
response => {
return response;
},
err => {
const originalRequest = err.config;
if (err.response.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise(function(resolve, reject) {
failedQueue.push({ resolve, reject });
})
.then(token => {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
return axios(originalRequest);
})
.catch(err => {
return Promise.reject(err);
});
}
originalRequest._retry = true;
isRefreshing = true;
return new Promise(function(resolve, reject) {
axios
.post('/fooUrl/refreshToken', {
refreshToken: "fooToken"})
.then(({ data }) => {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.fooToken;
originalRequest.headers['Authorization'] = 'Bearer ' + data.fooToken;
processQueue(null, data.fooToken);
resolve(axios(originalRequest));
})
.catch(err => {
processQueue(err, null);
store.dispatch(showMessage({ message: 'Expired Token' }));
reject(err);
})
.then(() => {
isRefreshing = false;
});
});
}
return Promise.reject(err);
}
);

Possible Unhandled Promise Rejection (id: 0): Error missing baseUrl

I'm getting this error every time I press a specific button on my react-native app. I'm guessing it has to do something with an Api call or maybe it is trying to invoke URLs with localhost:8081, which may not be correct as it should be pointing to a server. I'm not sure exactly how to pinpoint the problem. Any help would be much appreciated. I'm also now sure if the problem is coming from the file I shared underneath.
App Warning message:
This is my RestClient code:
import {Alert, AsyncStorage} from 'react-native'
import {resetRouteTo} from 'util/NavigationHelper'
import {store} from '../index.js'
import {dropdownAlert} from 'util/AlertManager'
const DEFAULT_ERROR = {error: {code: 500, message: 'No JSON message'}}
export default class RestClient {
constructor (baseUrl = '', navigation, { headers = {}, devMode = false, simulatedDelay = 0 } = {}) {
if (!baseUrl) throw new Error('missing baseUrl')
this.navigation = navigation
this.headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
Object.assign(this.headers, headers)
this.baseUrl = baseUrl
this.simulatedDelay = simulatedDelay
this.devMode = devMode
}
_clearTokenAndGo () {
AsyncStorage.removeItem('apiToken')
Alert.alert(
'Error',
'Something went wrong and your account needs to be re-instantiated.',
[
{text: 'OK', onPress: () => resetRouteTo(this.navigation, 'OnboardingFirst')}
],
{ cancelable: false }
)
}
_simulateDelay () {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, this.simulatedDelay)
})
}
async _parseIfJson (response) {
var contentType = response.headers.get('content-type')
if (contentType && contentType.indexOf('application/json') !== -1) {
return response.json()
}
return null
}
async _handleError (response) {
const body = await this._parseIfJson(response)
if (!body) {
dropdownAlert('error', `Server Error ${response.status}`, 'Something went wrong on the server')
return DEFAULT_ERROR
}
switch (response.status) {
case 200: {
break
}
case 401: {
if (body.error === 'Unauthenticated.') {
this._clearTokenAndGo()
}
break
}
case 400: {
dropdownAlert('error', `Error ${body.error.code}`, body.error.message)
break
}
default: {
if (body.error) {
dropdownAlert('error', `Error ${body.error.code}`, body.error.message)
} else {
dropdownAlert('error', 'Error', `An unknown error has occurred. Http status ${response.status}`)
}
break
}
}
return body
}
_fullRoute (url) {
return `${this.baseUrl}${url}`
}
async _fetch (route, method, body, isQuery = false) {
if (!route) throw new Error('Route is undefined')
if (!store.getState().netinfo.isConnected) {
this.navigation.navigate('BlockScreen')
return {success: false, error: {code: 1, message: 'No internet connection.'}}
}
var fullRoute = this._fullRoute(route)
if (isQuery && body) {
var qs = require('qs')
const query = qs.stringify(body)
fullRoute = `${fullRoute}?${query}`
body = undefined
}
let opts = {
method,
headers: this.headers
}
if (body) {
Object.assign(opts, { body: JSON.stringify(body) })
}
const fetchPromise = () => fetch(fullRoute, opts)
if (this.devMode && this.simulatedDelay > 0) {
// Simulate an n-second delay in every request
return this._simulateDelay()
.then(() => fetchPromise())
.then(response => response.json())
} else {
let promise = await fetch(fullRoute, opts)
console.log('Logging response =>')
console.log(promise)
return this._handleError(promise)
}
}
GET (route, query) { return this._fetch(route, 'GET', query, true) }
POST (route, body) { return this._fetch(route, 'POST', body) }
PUT (route, body) { return this._fetch(route, 'PUT', body) }
DELETE (route, query) { return this._fetch(route, 'DELETE', query, true) }
}
Other files using RestClient:
import RestClient from 'util/RestClientLib'
import qs from 'qs'
import { Linking, AsyncStorage } from 'react-native'
import Config from 'react-native-config'
var SHA256 = require('crypto-js/sha256')
export default class ApiClient extends RestClient {
constructor (authToken, navigation) {
console.log('constructing apiClient with base: ', Config.API_URL)
super(Config.API_URL, navigation, {
headers: {
'Authorization': 'Bearer ' + authToken
}
})
}
_switchSchemeTo (url, scheme) {
var split = url.split(':')
split[0] = scheme
return split.join(':')
}
_makeAppUrl (url) {
const prefix = url.split('.')[0]
const bank = prefix.substr(prefix.lastIndexOf('/') + 1, prefix.length)
switch (bank) {
case 'florijnbank':
return this._switchSchemeTo(url, 'flrb')
default:
return url
}
}
async _openUrl (url) {
const openInApp = await AsyncStorage.getItem('openInApp')
const appUrl = this._makeAppUrl(url)
Linking.canOpenURL(appUrl).then(supported => {
if (!supported || openInApp !== 'true') {
Linking.canOpenURL(url).then(supported => {
if (!supported) {
console.log('Can\'t handle url: ' + url)
} else {
Linking.openURL(url)
}
}).catch(err => console.error('An error occurred', err))
} else {
Linking.openURL(appUrl)
}
}).catch(err => console.error('An error occurred', err))
}
async createToken (pin) {
var hash = SHA256(pin).toString()
const query = {pincode: hash}
let response = await this.POST('/user', query)
return response.api_token
}
async checkPin (pin) {
const hash = SHA256(pin).toString()
const query = {pincode: hash}
return this.GET('/user/validate', query)
}
getAccounts () {
return this.GET('/account')
}
getBalance (iban) {
return this.GET(`/account/${iban}`)
}
async getPermissionBank (bank) {
const query = {
bank_id: bank
}
let response = await this.POST('/account', query)
return this._openUrl(response.url)
}
postCredentialsAis (form) {
return this.POST('/account/password', form)
}
async ais (iban) {
let response = await this.GET(`/ais/${iban}`)
if (response.url == null) {
return true
}
this._openUrl(response.url)
return false
}
getTransactionDetails (requestId) {
return this.GET(`/request/${requestId}`)
}
getTransactions (iban) {
return this.GET(`/account/${iban}/transaction`)
}
getContacts () {
return this.GET('/contacts')
}
getSettings () {
return this.GET('/startup')
}
deleteAccount (iban) {
return this.DELETE(`/account/${iban}`)
}
/**
* async submitTransfer - submits a transfer
*
* #param {Object} options object which holds the pin, iban, sso and query
* #param {Object} transfer hold the transfer information
* #return {Boolean} either opens a link or a boolean for success
*/
submitTransfer (iban, credentials, transfer) {
const url = `/account/${iban}/transaction?${qs.stringify(credentials)}`
const body = {
counter_iban: transfer.counterIban,
counter_account_name: transfer.name,
amount: transfer.amount,
description: transfer.description,
reference: transfer.reference
}
return this.POST(url, body)
}
qrConfirmTransfer (transactionId, iban, credentials) {
const url = `/request/${transactionId}/confirm/${iban}?${qs.stringify(credentials)}`
return this.POST(url)
}
directConfirmTransfer (transactionId, iban, form) {
const url = `/account/${iban}/transaction/${transactionId}`
return this.POST(url, form)
}
verificationRequired (iban, amount) {
const query = {amount: amount}
return this.GET(`/veriReq/${iban}`, query)
}
};

Categories