mirror of
https://github.com/bellingcat/auto-archiver-setup-tool.git
synced 2026-06-08 03:28:37 +03:00
428 lines
13 KiB
JavaScript
428 lines
13 KiB
JavaScript
import { createStore } from "vuex";
|
|
import { gapi } from "@/gapi";
|
|
import {
|
|
signOut,
|
|
GoogleAuthProvider,
|
|
signInWithCredential,
|
|
browserLocalPersistence,
|
|
setPersistence,
|
|
} from "firebase/auth";
|
|
import { firebaseAuth } from "@/firebase.js";
|
|
|
|
function saveToLocalStorage(state) {
|
|
localStorage.setItem("user", JSON.stringify(state.user));
|
|
localStorage.setItem("access_token", state.access_token);
|
|
}
|
|
|
|
function loadFromLocalStorage() {
|
|
const user = JSON.parse(localStorage.getItem("user"));
|
|
const access_token = localStorage.getItem("access_token");
|
|
return { user, access_token };
|
|
}
|
|
|
|
function clearLocalStorage() {
|
|
localStorage.removeItem("user");
|
|
localStorage.removeItem("access_token");
|
|
}
|
|
|
|
async function waitForGapiAuth2() {
|
|
return new Promise((resolve, _reject) => {
|
|
const checkGapiAuth2 = () => {
|
|
if (gapi.auth2 && gapi.auth2.getAuthInstance()) {
|
|
resolve(gapi.auth2.getAuthInstance());
|
|
} else {
|
|
setTimeout(checkGapiAuth2, 100);
|
|
}
|
|
};
|
|
checkGapiAuth2();
|
|
});
|
|
}
|
|
|
|
export default createStore({
|
|
state: {
|
|
user: null,
|
|
active: false,
|
|
access_token: null,
|
|
sheets: [],
|
|
loadingUserState: false,
|
|
errorMessage: "",
|
|
// API_ENDPOINT: "https://auto-archiver-api.bellingcat.com"
|
|
API_ENDPOINT: process.env.VUE_APP_API_ENDPOINT || "http://localhost:8004",
|
|
},
|
|
mutations: {
|
|
setUser(state, user) {
|
|
state.user = user;
|
|
saveToLocalStorage(state);
|
|
},
|
|
setUserActiveState(state, active) {
|
|
state.user.active = active;
|
|
saveToLocalStorage(state);
|
|
},
|
|
setUserPermissions(state, permissions) {
|
|
state.user.permissions = permissions;
|
|
state.user.groups = Object.keys(permissions).filter(
|
|
(key) => key !== "all"
|
|
);
|
|
state.loadingUserState = false;
|
|
saveToLocalStorage(state);
|
|
},
|
|
setUserUsage(state, usage) {
|
|
state.user.usage = usage;
|
|
},
|
|
setSheets(state, sheets) {
|
|
state.sheets = sheets;
|
|
},
|
|
setLoadingUserState(state, loadingUserState) {
|
|
state.loadingUserState = loadingUserState;
|
|
saveToLocalStorage(state);
|
|
},
|
|
setAccessToken(state, access_token) {
|
|
state.access_token = access_token;
|
|
saveToLocalStorage(state);
|
|
},
|
|
setErrorMessage(state, errorMessage) {
|
|
state.errorMessage = errorMessage;
|
|
},
|
|
},
|
|
actions: {
|
|
async signin({ commit, dispatch }) {
|
|
commit("setLoadingUserState", true);
|
|
async function callback(tokenResponse) {
|
|
let access_token = tokenResponse.access_token;
|
|
commit("setAccessToken", access_token);
|
|
const credential = GoogleAuthProvider.credential(null, access_token);
|
|
|
|
// Set persistence before signing in
|
|
await setPersistence(firebaseAuth, browserLocalPersistence);
|
|
|
|
// Sign in with the provided credential
|
|
const response = await signInWithCredential(firebaseAuth, credential);
|
|
|
|
commit("setUser", response.user);
|
|
dispatch("checkActiveUser");
|
|
dispatch("checkUserPermissions");
|
|
dispatch("checkUserUsage");
|
|
}
|
|
|
|
commit("setUser", null);
|
|
|
|
const client = google.accounts.oauth2.initTokenClient({
|
|
client_id:
|
|
"406209235111-r1mpkvkfaqc2jg5iqbvffl2b0rf4clbo.apps.googleusercontent.com",
|
|
scope:
|
|
"https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
|
|
callback,
|
|
});
|
|
|
|
await client.requestAccessToken();
|
|
},
|
|
|
|
async signout({ commit }) {
|
|
try {
|
|
const authInstance = await waitForGapiAuth2();
|
|
if (authInstance) {
|
|
await authInstance.signOut();
|
|
console.log("User is signed out from gapi.");
|
|
} else {
|
|
console.warn("gapi.auth2 is not initialized.");
|
|
}
|
|
|
|
await signOut(firebaseAuth);
|
|
console.log("User is signed out from firebase.");
|
|
|
|
// clean user from store and local storage
|
|
commit("setUser", null);
|
|
commit("setSheets", []);
|
|
clearLocalStorage();
|
|
} catch (error) {
|
|
console.error("signOutUser (firebase/auth.js): ", error);
|
|
} finally {
|
|
commit("setLoadingUserState", false);
|
|
}
|
|
},
|
|
|
|
async checkActiveUser({ state, dispatch, commit }) {
|
|
try {
|
|
commit("setErrorMessage", "");
|
|
console.log(`${state.API_ENDPOINT}/user/active`);
|
|
const r = await fetch(`${state.API_ENDPOINT}/user/active`, {
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${state.access_token}`,
|
|
},
|
|
});
|
|
const response = await r.json();
|
|
commit("setUserActiveState", response.active);
|
|
if (response.active === true) {
|
|
dispatch("getSheets");
|
|
}
|
|
} catch (error) {
|
|
console.error("checkActiveUser (firebase.js): ", error);
|
|
commit(
|
|
"setErrorMessage",
|
|
"Unable to check user status against the API"
|
|
);
|
|
}
|
|
},
|
|
|
|
async checkUserPermissions({ state, commit }) {
|
|
try {
|
|
commit("setErrorMessage", "");
|
|
const r = await fetch(`${state.API_ENDPOINT}/user/permissions`, {
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${state.access_token}`,
|
|
},
|
|
});
|
|
const response = await r.json();
|
|
commit("setUserPermissions", response);
|
|
} catch (error) {
|
|
console.error("checkUserPermissions (firebase.js): ", error);
|
|
commit(
|
|
"setErrorMessage",
|
|
"Unable to fetch user permissions from the API"
|
|
);
|
|
}
|
|
},
|
|
async checkUserUsage({ state, commit }) {
|
|
try {
|
|
commit("setErrorMessage", "");
|
|
const r = await fetch(`${state.API_ENDPOINT}/user/usage`, {
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${state.access_token}`,
|
|
},
|
|
});
|
|
const response = await r.json();
|
|
commit("setUserUsage", response);
|
|
} catch (error) {
|
|
console.error("checkUserUsage (firebase.js): ", error);
|
|
commit(
|
|
"setErrorMessage",
|
|
"Unable to fetch user usage quota from the API"
|
|
);
|
|
}
|
|
},
|
|
|
|
async getSheets({ state, commit }) {
|
|
try {
|
|
commit("setErrorMessage", "");
|
|
if (state.user?.active === false) return;
|
|
|
|
fetch(`${state.API_ENDPOINT}/sheet/mine`, {
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${state.access_token}`,
|
|
},
|
|
}).then(async (response) => {
|
|
const res = await response.json();
|
|
if (response.status === 200) {
|
|
commit("setSheets", res);
|
|
} else {
|
|
throw new Error(JSON.stringify(res));
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error("getSheets (firebase.js): ", error);
|
|
}
|
|
},
|
|
async createSheet(
|
|
{ _state, dispatch, _commit },
|
|
{ name, service_account_email }
|
|
) {
|
|
return new Promise(async (resolve, reject) => {
|
|
try {
|
|
// create new sheet
|
|
const newSheet = await gapi.client.sheets.spreadsheets.create({
|
|
properties: {
|
|
title: name,
|
|
},
|
|
});
|
|
|
|
const spreadsheetId = newSheet.result.spreadsheetId;
|
|
|
|
const userEnteredFormat = {
|
|
textFormat: {
|
|
bold: true,
|
|
},
|
|
};
|
|
|
|
// add header row
|
|
await gapi.client.sheets.spreadsheets.batchUpdate(
|
|
{
|
|
spreadsheetId: spreadsheetId,
|
|
},
|
|
{
|
|
requests: [
|
|
{
|
|
updateCells: {
|
|
rows: [
|
|
{
|
|
values: [
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Link",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Archive status",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Archive location",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Archive date",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Thumbnail",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Upload timestamp",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Upload title",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Textual content",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Screenshot",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
{
|
|
userEnteredValue: {
|
|
stringValue: "Hash",
|
|
},
|
|
userEnteredFormat,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
fields:
|
|
"userEnteredValue.stringValue,userEnteredFormat.textFormat.bold",
|
|
start: {
|
|
sheetId: 0,
|
|
rowIndex: 0,
|
|
columnIndex: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
addProtectedRange: {
|
|
protectedRange: {
|
|
range: {
|
|
sheetId: 0,
|
|
startRowIndex: 0,
|
|
endRowIndex: 1,
|
|
startColumnIndex: 0,
|
|
endColumnIndex: 11,
|
|
},
|
|
description:
|
|
"Protecting header row (needed for auto-archiver), do not modify archiving column names, you can add and move columns around when no 'Archive in Progress' is present in the 'Archive status' column.",
|
|
warningOnly: true,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
}
|
|
);
|
|
|
|
// add permissions
|
|
// TODO: make sure this emailAdress is used according to the group
|
|
await gapi.client.drive.permissions.create({
|
|
fileId: spreadsheetId,
|
|
resource: {
|
|
role: "writer",
|
|
type: "user",
|
|
emailAddress: service_account_email,
|
|
},
|
|
});
|
|
|
|
resolve({ success: true, result: spreadsheetId });
|
|
} catch (error) {
|
|
console.error("add (firebase.js): ", error);
|
|
if (error.status === 401) {
|
|
await dispatch("signout");
|
|
}
|
|
reject({ success: false, result: error });
|
|
}
|
|
});
|
|
},
|
|
},
|
|
getters: {
|
|
isTokenExpired: async (state) => {
|
|
if (!state.access_token) return true;
|
|
try {
|
|
const response = await fetch(
|
|
`https://oauth2.googleapis.com/tokeninfo?access_token=${state.access_token}`
|
|
);
|
|
if (response.status !== 200) return true;
|
|
const data = await response.json();
|
|
if (data.expires_in > 0) return false;
|
|
} catch (error) {
|
|
console.error("Error checking token expiration:", error);
|
|
return true;
|
|
}
|
|
},
|
|
},
|
|
modules: {},
|
|
plugins: [
|
|
(store) => {
|
|
store.subscribe((mutation, state) => {
|
|
if (mutation.type === "setUser" || mutation.type === "setAccessToken") {
|
|
saveToLocalStorage(state);
|
|
}
|
|
});
|
|
|
|
const { user, access_token } = loadFromLocalStorage();
|
|
if (user && access_token) {
|
|
store.commit("setLoadingUserState", true);
|
|
store.commit("setUser", user);
|
|
store.commit("setAccessToken", access_token);
|
|
store.getters.isTokenExpired
|
|
.then((expired) => {
|
|
if (expired) {
|
|
store.dispatch("signout");
|
|
} else {
|
|
store.dispatch("checkActiveUser");
|
|
store.dispatch("checkUserPermissions");
|
|
store.dispatch("checkUserUsage");
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.error("Error checking token expiration:", error);
|
|
store.dispatch("signout");
|
|
});
|
|
}
|
|
},
|
|
],
|
|
});
|