File "IpAddressDataTableStore.js"
Full Path: /home/bytebmoc/tideswithin.com/LimitLoginAttempts/IpAddressDataTableStore.js
File size: 13.78 KB
MIME-type: text/x-java
Charset: utf-8
/* Creates A Store For Risk Data using Zustand */
import {create} from 'zustand';
import * as rsssl_api from "../../utils/api";
import {produce} from "immer";
const IpAddressDataTableStore = create((set, get) => ({
processing: false,
dataLoaded: false,
ipAddress: '',
highestIP: '',
lowestIP: '',
statusSelected: 'blocked',
inputRangeValidated: false,
cidr: '',
ip_count: '',
canSetCidr: false,
ipRange: {},
idSelected: '',
pagination: {},
dataActions: {},
IpDataTable: [],
maskError: false,
rowCleared: false,
setMaskError: (maskError) => {
set({maskError});
},
/*
* This function fetches the data from the server and fills the property IpDataTable
* Note this function works with the DataTable class on serverside
*/
fetchData: async (action, dataActions) => {
set({processing: true});
set({dataLoaded: false});
set({rowCleared: true});
//if the dataActions is empty we do nothing
if (Object.keys(dataActions).length === 0) {
return;
}
try {
const response = await rsssl_api.doAction(
action,
dataActions
);
//now we set the EventLog
if (response) {
//if the response is empty we set the dummyData
set({IpDataTable: response, dataLoaded: true, processing: false, pagination: response.pagination});
}
} catch (e) {
console.log(e);
} finally {
set({processing: false});
set({rowCleared: false});
}
},
/*
* This function handles the search, it is called from the search from it's parent class
*/
handleIpTableSearch: async (search, searchColumns) => {
//Add the search to the dataActions
set(produce((state) => {
state.dataActions = {...state.dataActions, search, searchColumns};
})
);
},
/*
* This function handles the page change, it is called from the DataTable class
*/
handleIpTablePageChange: async (page, pageSize) => {
//Add the page and pageSize to the dataActions
set(produce((state) => {
state.dataActions = {...state.dataActions, page, pageSize};
})
);
},
/*
* This function handles the rows change, it is called from the DataTable class
*/
handleIpTableRowsChange: async (currentRowsPerPage, currentPage) => {
//Add the page and pageSize to the dataActions
set(produce((state) => {
state.dataActions = {...state.dataActions, currentRowsPerPage, currentPage};
})
);
},
/*
* This function handles the sort, it is called from the DataTable class
*/
handleIpTableSort: async (column, sortDirection) => {
//Add the column and sortDirection to the dataActions
set(produce((state) => {
state.dataActions = {...state.dataActions, sortColumn: column, sortDirection};
})
);
},
/*
* This function handles the filter, it is called from the GroupSetting class
*/
handleIpTableFilter: async (column, filterValue) => {
//Add the column and sortDirection to the dataActions
set(produce((state) => {
state.dataActions = {...state.dataActions, filterColumn: column, filterValue};
})
);
},
/*
* This function sets the ip address and is used by Cidr and IpAddressInput
*/
setIpAddress: (ipAddress) => {
if(ipAddress.length === 0) {
return;
}
let ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,4}|((25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9]))|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9]))$/;
if (ipAddress.includes('/')) {
let finalIp = '';
// Split the input into IP and CIDR mask
let [ip, mask] = ipAddress.split('/');
//if , we change it to .
ip = ip.replace(/,/g, '.');
if (mask.length <= 0 ) {
if (!ipRegex.test(ip)) {
set({maskError: true});
} else {
set({maskError: false});
}
finalIp = `${ip}/${mask}`;
} else {
finalIp = mask ? `${ip}/${mask}` : ip;
}
set({ ipAddress: finalIp })
} else {
if (!ipRegex.test(ipAddress)) {
set({maskError: true});
} else {
set({maskError: false});
}
set({ ipAddress: ipAddress.replace(/,/g, '.') })
}
},
resetRange: () => {
set({inputRangeValidated: false});
set({highestIP: ''});
set({lowestIP: ''});
set({ipAddress: ''});
set({maskError: false});
},
/*
* This function sets the status selected and is used by Cidr and IpAddressInput and from the options
*/
setStatusSelected: (statusSelected) => {
set({statusSelected});
},
/*
* This function sets the id selected and is used by Cidr and IpAddressInput and from the options
*/
setId: (idSelected) => {
set({idSelected});
},
/*
* This function updates the row only changing the status
*/
/*
* This function updates the row only changing the status
*/
updateRow: async (value, status, dataActions) => {
set({processing: true});
let data = {
value: value,
status: status
};
try {
const response = await rsssl_api.doAction(
'ip_update_row',
data
);
if (response && response.request_success) {
await get().fetchData('rsssl_limit_login', dataActions);
return { success: true, message: response.message, response };
} else {
return { success: false, message: response?.message || 'Failed to add ip', response };
}
} catch (e) {
return { success: false, message: 'Error occurred', error: e };
} finally {
set({processing: false});
}
},
/**
* This function validates the ip address string if it is a proper ip address
* This checks ipv4 addresses
*
* @param ip
* @returns {boolean}
*/
validateIpv4: (ip) => {
const parts = ip.split(".");
if (parts.length !== 4) return false;
for (let part of parts) {
const num = parseInt(part, 10);
if (isNaN(num) || num < 0 || num > 255) return false;
}
return true;
},
/**
* This function validates the ip address string if it is a proper ip address
* This checks ipv6 addresses
*
* @param ip
* @returns {boolean}
*/
validateIpv6: (ip) => {
const parts = ip.split(":");
if (parts.length !== 8) return false;
for (let part of parts) {
if (part.length > 4 || !/^[0-9a-fA-F]+$/.test(part)) return false;
}
return true;
},
extendIpV6: (ip) => {
// Handle the special case of '::' at the start or end
if (ip === '::') ip = '0::0';
// Handle the '::' within the address
if (ip.includes('::')) {
const parts = ip.split('::');
if (parts.length > 2) return false;
const left = parts[0].split(':').filter(Boolean);
const right = parts[1].split(':').filter(Boolean);
// Calculate how many zeros are needed
const zerosNeeded = 8 - (left.length + right.length);
// Concatenate all parts with the appropriate number of zeros
return [...left, ...Array(zerosNeeded).fill('0'), ...right].join(':');
}
return ip;
},
/**
* This function converts the ip address to a number
*
* @param ip
* @returns {*}
*/
ipToNumber: (ip) => {
if (get().validateIpv4(ip)) {
return get().ipV4ToNumber(ip);
} else if (get().validateIpv6(get().extendIpV6(ip))) {
return get().ipV6ToNumber(get().extendIpV6(ip));
}
},
/**
* This function converts the ip address to a number if it is a ipv4 address
* @param ip
* @returns {*}
*/
ipV4ToNumber: (ip) => {
return ip.split(".").reduce((acc, cur) => (acc * 256 + parseInt(cur, 10)) >>> 0, 0);
},
/**
* This function converts the ip address to a number if it is a ipv6 address
* @param ip
* @returns {*}
*/
ipV6ToNumber: (ip) => {
return ip.split(":").reduce((acc, cur) => {
const segmentValue = parseInt(cur, 16);
if (isNaN(segmentValue)) {
console.warn(`Invalid segment in IPv6 address: ${oldIp}`);
return acc;
}
return (acc << BigInt(16)) + BigInt(segmentValue);
}, BigInt(0));
},
/**
* This function validates the ip range, if the lowest is lower than the highest
* This checks ipv4 and ipv6 addresses
*
* @param lowest
* @param highest
*/
validateIpRange: (lowest, highest) => {
set({inputRangeValidated: false});
let from = '';
let to = '';
//first we determine if the IP is ipv4 or ipv6
if (lowest && highest) {
if (get().validateIpv4(lowest) && get().validateIpv4(highest)) {
//now we check if the lowest is lower than the highest
if (get().ipToNumber(lowest) > get().ipToNumber(highest)) {
console.warn('lowest is higher than highest');
set({inputRangeValidated: false});
return;
}
from = lowest;
to = highest;
set({inputRangeValidated: true});
} else if (get().validateIpv6(get().extendIpV6(lowest)) && get().validateIpv6(get().extendIpV6(highest))) {
//now we check if the lowest is lower than the highest
if (get().ipToNumber(get().extendIpV6(lowest)) > get().ipToNumber(get().extendIpV6(highest))) {
console.warn('lowest is higher than highest');
set({inputRangeValidated: false});
return;
}
from = get().extendIpV6(lowest);
to = get().extendIpV6(highest);
set({inputRangeValidated: true});
}
}
if (get().inputRangeValidated) {
let lowest = from;
let highest = to;
set({ipRange: {lowest, highest}});
get().fetchCidrData('get_mask_from_range');
}
},
/**
* This function fetches the cidr data from the server and sets the cidr and ip_count
* This function is called from the Cidr class
*
* @param action
* @returns {Promise<void>}
*/
fetchCidrData: async (action) => {
try {
const response = await rsssl_api.doAction(
action,
get().ipRange
);
//now we set the EventLog
if (response) {
//we set the cidrFound and cidrCount
set({cidr: response.cidr, ipAddress: response.cidr, ip_count: response.ip_count, canSetCidr: true});
//we reload the event log
}
} catch (e) {
console.log(e);
}
},
resetRow: async (id, dataActions) => {
set({processing: true});
try {
const response = await rsssl_api.doAction(
'delete_entries',
{id}
);
//now we set the EventLog
if (response && response.success) {
await get().fetchData('rsssl_limit_login', dataActions);
// Return the success message from the API response.
return { success: true, message: response.message, response };
} else {
// Return a custom error message or the API response message.
return { success: false, message: response?.message || 'Failed to reset ip', response };
}
} catch (e) {
console.error(e);
// Return the caught error with a custom message.
return { success: false, message: 'Error occurred', error: e };
} finally {
set({processing: false});
}
},
resetMultiRow: async (ids, dataActions) => {
set({processing: true});
try {
const response = await rsssl_api.doAction(
'delete_entries',
{ids}
);
//now we set the EventLog
if (response && response.success) {
if (response.success) {
await get().fetchData('rsssl_limit_login', dataActions);
return {success: true, message: response.message, response};
} else
return {success: false, message: response?.message || 'Failed to reset ip', response};
}
} catch (e) {
console.error(e);
return { success: false, message: 'Error occurred', error: e };
} finally {
set({processing: false});
}
}
}));
export default IpAddressDataTableStore;