2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* This file implements authentication related actions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// NPM imports
|
2016-07-07 23:23:18 +02:00
|
|
|
import { push } from "react-router-redux";
|
|
|
|
import Cookies from "js-cookie";
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
// Local imports
|
|
|
|
import { buildHMAC, cleanURL } from "../utils";
|
2016-07-07 23:23:18 +02:00
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
// Models
|
2016-08-01 00:26:52 +02:00
|
|
|
import { i18nRecord } from "../models/i18n";
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
// Other actions and payload types
|
|
|
|
import { CALL_API } from "../middleware/api";
|
|
|
|
import { invalidateStore } from "./store";
|
2016-07-07 23:23:18 +02:00
|
|
|
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
// Constants
|
|
|
|
export const DEFAULT_SESSION_INTERVAL = 1800 * 1000; // 30 mins long sessoins by default
|
2016-07-07 23:23:18 +02:00
|
|
|
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* Dispatch a ping query to the API for login keepalive and prevent session
|
|
|
|
* from expiring.
|
|
|
|
*
|
|
|
|
* @param username Username to use
|
|
|
|
* @param token Token to revive
|
|
|
|
* @param endpoint Ampache base URL
|
|
|
|
*
|
|
|
|
* @return A CALL_API payload to keep session alive.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function loginKeepAlive(username, token, endpoint) {
|
|
|
|
return {
|
|
|
|
type: CALL_API,
|
|
|
|
payload: {
|
|
|
|
endpoint: endpoint,
|
|
|
|
dispatch: [
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
error => dispatch => {
|
2016-08-01 00:26:52 +02:00
|
|
|
dispatch(loginUserFailure(error || new i18nRecord({ id: "app.login.expired", values: {}})));
|
2016-08-10 23:50:23 +02:00
|
|
|
},
|
2016-07-07 23:23:18 +02:00
|
|
|
],
|
|
|
|
action: "ping",
|
|
|
|
auth: token,
|
|
|
|
username: username,
|
2016-08-10 23:50:23 +02:00
|
|
|
extraParams: {},
|
|
|
|
},
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
2016-07-07 23:23:18 +02:00
|
|
|
export const LOGIN_USER_SUCCESS = "LOGIN_USER_SUCCESS";
|
2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* Action to be called on successful login.
|
|
|
|
*
|
|
|
|
* @param username Username used for login
|
|
|
|
* @param token Token got back from the API
|
|
|
|
* @param endpoint Ampache server base URL
|
|
|
|
* @param rememberMe Whether to remember me or not
|
|
|
|
* @param timerID ID of the timer set for session keepalive.
|
|
|
|
*
|
|
|
|
* @return A login success payload.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function loginUserSuccess(username, token, endpoint, rememberMe, timerID) {
|
|
|
|
return {
|
|
|
|
type: LOGIN_USER_SUCCESS,
|
|
|
|
payload: {
|
|
|
|
username: username,
|
|
|
|
token: token,
|
|
|
|
endpoint: endpoint,
|
|
|
|
rememberMe: rememberMe,
|
2016-08-10 23:50:23 +02:00
|
|
|
timerID: timerID,
|
|
|
|
},
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
2016-07-07 23:23:18 +02:00
|
|
|
export const LOGIN_USER_FAILURE = "LOGIN_USER_FAILURE";
|
2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* Action to be called on failed login.
|
|
|
|
*
|
|
|
|
* This action removes any remember me cookie if any was set.
|
|
|
|
*
|
|
|
|
* @param error An error object, either string or i18nRecord.
|
|
|
|
* @return A login failure payload.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function loginUserFailure(error) {
|
|
|
|
Cookies.remove("username");
|
|
|
|
Cookies.remove("token");
|
|
|
|
Cookies.remove("endpoint");
|
|
|
|
return {
|
|
|
|
type: LOGIN_USER_FAILURE,
|
|
|
|
payload: {
|
2016-08-10 23:50:23 +02:00
|
|
|
error: error,
|
|
|
|
},
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
2016-08-06 17:20:02 +02:00
|
|
|
export const LOGIN_USER_EXPIRED = "LOGIN_USER_EXPIRED";
|
2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* Action to be called when session is expired.
|
|
|
|
*
|
|
|
|
* @param error An error object, either a string or i18nRecord.
|
|
|
|
* @return A session expired payload.
|
|
|
|
*/
|
2016-08-06 17:20:02 +02:00
|
|
|
export function loginUserExpired(error) {
|
|
|
|
return {
|
|
|
|
type: LOGIN_USER_EXPIRED,
|
|
|
|
payload: {
|
2016-08-10 23:50:23 +02:00
|
|
|
error: error,
|
|
|
|
},
|
2016-08-06 17:20:02 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
2016-07-07 23:23:18 +02:00
|
|
|
export const LOGIN_USER_REQUEST = "LOGIN_USER_REQUEST";
|
2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* Action to be called when login is requested.
|
|
|
|
*
|
|
|
|
* @return A login request payload.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function loginUserRequest() {
|
|
|
|
return {
|
2016-08-10 23:50:23 +02:00
|
|
|
type: LOGIN_USER_REQUEST,
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
2016-07-07 23:23:18 +02:00
|
|
|
export const LOGOUT_USER = "LOGOUT_USER";
|
2016-08-10 21:36:11 +02:00
|
|
|
/**
|
|
|
|
* Action to be called upon logout.
|
|
|
|
*
|
|
|
|
* This function clears the cookies set for remember me and the keep alive
|
|
|
|
* timer.
|
|
|
|
*
|
|
|
|
* @remark This function does not clear the other stores, nor handle
|
|
|
|
* redirection.
|
|
|
|
*
|
|
|
|
* @return A logout payload.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function logout() {
|
|
|
|
return (dispatch, state) => {
|
|
|
|
const { auth } = state();
|
|
|
|
if (auth.timerID) {
|
|
|
|
clearInterval(auth.timerID);
|
|
|
|
}
|
|
|
|
Cookies.remove("username");
|
|
|
|
Cookies.remove("token");
|
|
|
|
Cookies.remove("endpoint");
|
|
|
|
dispatch({
|
2016-08-10 23:50:23 +02:00
|
|
|
type: LOGOUT_USER,
|
2016-07-07 23:23:18 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to be called to log a user out.
|
|
|
|
*
|
|
|
|
* This function clears the remember me cookies and the keepalive timer. It
|
|
|
|
* also clears the data behind authentication in the store and redirects to
|
|
|
|
* login page.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function logoutAndRedirect() {
|
|
|
|
return (dispatch) => {
|
|
|
|
dispatch(logout());
|
2016-08-03 15:52:47 +02:00
|
|
|
dispatch(invalidateStore());
|
2016-07-07 23:23:18 +02:00
|
|
|
dispatch(push("/login"));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:36:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to be called to log a user in.
|
|
|
|
*
|
|
|
|
* @param username Username to use.
|
|
|
|
* @param passwordOrToken User password, or previous token to revive.
|
|
|
|
* @param endpoint Ampache server base URL.
|
|
|
|
* @param rememberMe Whether to rememberMe or not
|
|
|
|
* @param[optional] redirect Page to redirect to after login.
|
|
|
|
* @param[optional] isToken Whether passwordOrToken is a password or a
|
|
|
|
* token.
|
|
|
|
*
|
|
|
|
* @return A CALL_API payload to perform login.
|
|
|
|
*/
|
2016-07-07 23:23:18 +02:00
|
|
|
export function loginUser(username, passwordOrToken, endpoint, rememberMe, redirect="/", isToken=false) {
|
2016-08-10 21:36:11 +02:00
|
|
|
// Clean endpoint
|
|
|
|
endpoint = cleanURL(endpoint);
|
|
|
|
|
|
|
|
// Get passphrase and time parameters
|
2016-08-05 00:00:25 +02:00
|
|
|
let time = 0;
|
|
|
|
let passphrase = passwordOrToken;
|
2016-07-07 23:23:18 +02:00
|
|
|
if (!isToken) {
|
|
|
|
// Standard password connection
|
2016-08-10 21:36:11 +02:00
|
|
|
const HMAC = buildHMAC(passwordOrToken);
|
2016-07-07 23:23:18 +02:00
|
|
|
time = HMAC.time;
|
|
|
|
passphrase = HMAC.passphrase;
|
|
|
|
} else {
|
|
|
|
// Remember me connection
|
|
|
|
if (passwordOrToken.expires < new Date()) {
|
|
|
|
// Token has expired
|
2016-08-01 12:01:11 +02:00
|
|
|
return loginUserFailure("app.login.expired");
|
2016-07-07 23:23:18 +02:00
|
|
|
}
|
|
|
|
time = Math.floor(Date.now() / 1000);
|
|
|
|
passphrase = passwordOrToken.token;
|
|
|
|
}
|
2016-08-10 21:36:11 +02:00
|
|
|
|
2016-07-07 23:23:18 +02:00
|
|
|
return {
|
|
|
|
type: CALL_API,
|
|
|
|
payload: {
|
|
|
|
endpoint: endpoint,
|
|
|
|
dispatch: [
|
|
|
|
loginUserRequest,
|
|
|
|
jsonData => dispatch => {
|
|
|
|
if (!jsonData.auth || !jsonData.sessionExpire) {
|
2016-08-10 21:36:11 +02:00
|
|
|
// On success, check that we are actually authenticated
|
2016-08-02 13:07:12 +02:00
|
|
|
return dispatch(loginUserFailure(new i18nRecord({ id: "app.api.error", values: {} })));
|
2016-07-07 23:23:18 +02:00
|
|
|
}
|
2016-08-10 21:36:11 +02:00
|
|
|
// Get token from the API
|
2016-07-07 23:23:18 +02:00
|
|
|
const token = {
|
|
|
|
token: jsonData.auth,
|
2016-08-10 23:50:23 +02:00
|
|
|
expires: new Date(jsonData.sessionExpire),
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
2016-08-10 21:36:11 +02:00
|
|
|
// Handle session keep alive timer
|
2016-07-07 23:23:18 +02:00
|
|
|
const timerID = setInterval(
|
|
|
|
() => dispatch(loginKeepAlive(username, token.token, endpoint)),
|
|
|
|
DEFAULT_SESSION_INTERVAL
|
|
|
|
);
|
|
|
|
if (rememberMe) {
|
2016-08-10 21:36:11 +02:00
|
|
|
// Handle remember me option
|
2016-07-07 23:23:18 +02:00
|
|
|
const cookiesOption = { expires: token.expires };
|
|
|
|
Cookies.set("username", username, cookiesOption);
|
|
|
|
Cookies.set("token", token, cookiesOption);
|
|
|
|
Cookies.set("endpoint", endpoint, cookiesOption);
|
|
|
|
}
|
2016-08-10 21:36:11 +02:00
|
|
|
// Dispatch login success
|
2016-07-07 23:23:18 +02:00
|
|
|
dispatch(loginUserSuccess(username, token, endpoint, rememberMe, timerID));
|
|
|
|
// Redirect
|
|
|
|
dispatch(push(redirect));
|
|
|
|
},
|
2016-08-10 23:50:23 +02:00
|
|
|
loginUserFailure,
|
2016-07-07 23:23:18 +02:00
|
|
|
],
|
|
|
|
action: "handshake",
|
|
|
|
auth: passphrase,
|
|
|
|
username: username,
|
2016-08-10 23:50:23 +02:00
|
|
|
extraParams: {timestamp: time},
|
|
|
|
},
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
|
|
|
}
|