MRBS 1.12.2 等保2.0二级整改完整提交
Docker image / push (push) Canceled after 0s

包含:登录失败锁定、90天密码有效期、30分钟会话超时、
强制改密、登录审计日志、屏幕水印、企业背景图、
备案信息固定底部、favicon、登录页JS修复等全部改动
This commit is contained in:
人事系统开发
2026-09-08 21:19:47 +08:00
commit 48092cab42
2221 changed files with 659586 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
import {forbidden, ok, serverError} from 'wix-http-functions';
import {authentication} from 'wix-members-backend';
import wixData from 'wix-data';
import {contacts} from 'wix-crm-backend';
import wixSecretsBackend from 'wix-secrets-backend';
// Validates that a request is valid, ie that the requesting server has used
// a valid API key, ie one that matches the one held in the Wix secrets manager.
// Parameters:
// request the request
// data the data in the request which must include
// key the API key
// secret_name the name of the secret in the Wix secrets manager that holds the API key
function validateRequest(request, data) {
return wixSecretsBackend.getSecret(data.secret_name)
.then((secret) => {
if (secret === data.key) {
return true;
}
else {
console.log("MRBS: invalid API key passed by IP address " + request.headers['x-real-ip']);
return false;
}
})
.catch((error) => {
console.error(error);
return false;
})
}
// The exported functions work by firing off two promises in parallel: the first
// validates that the request comes from an authorised server and the second does
// the actual work. When the two promises have been resolved or rejected, this
// function processes the promise results and issues the appropriate response.
function processPromiseResults(promiseResults) {
let result = {
"headers": {
"Content-Type": "application/json"
}
}
if ((promiseResults[0].status === 'rejected') || (promiseResults[1].status === 'rejected')) {
result.body = "internal server error";
return serverError(result);
}
else if (promiseResults[0].value === false) {
result.body = "forbidden";
return forbidden(result);
}
else {
result.body = promiseResults[1].value;
return ok(result);
}
}
// Validates a member's email login and password. Returns a boolean.
// Request data parameters:
// email the member's login email address
// password the password
export async function post_validateMember(request) {
const data = await request.body.json();
const validateRequestPromise = validateRequest(request, data);
const validateMemberPromise = authentication.login(data.email, data.password)
.then(() => {
return true;
})
.catch((error) => {
// If the email address and password are not valid then we will get
// an UNAUTHORIZED error. If it's any other kind then log it.
if (error.details.applicationError.code === "UNAUTHORIZED") {
console.error(error);
}
// Return false whatever the error
return false;
});
return Promise.allSettled([validateRequestPromise, validateMemberPromise])
.then((promiseResults) => {
return processPromiseResults(promiseResults);
})
}
// Gets a member's details given an email address. Returns a JSON object or NULL.
// Request data parameters:
// email the member's login email address
export async function post_getMemberByEmail(request) {
const data = await request.body.json();
const options = {
"suppressAuth": true,
"suppressHooks": true
};
const validateRequestPromise = validateRequest(request, data);
const getMemberPromise = wixData.query("Members/PrivateMembersData")
.eq("loginEmail", data.email)
.limit(1)
.find(options)
.then((members) => {
if(members.items.length > 0) {
let member = members.items[0];
// Now we've got the member we have to get (a) their full details (including
// custom fields, which aren't in PrivateMembersData) from Contacts using
// the id and (b) their badges from Members/Badges. Get these two sets of
// data in parallel using promises.
const getContactPromise = contacts.getContact(member._id, {suppressAuth: true})
.then((contact) => {
return {
member: member,
contact: contact
};
})
.catch((error) => {
console.error(error);
return null;
});
const getBadgesPromise = wixData.query("Members/Badges")
.find()
.then((results) => {
return results.items;
} );
return Promise.allSettled([getContactPromise, getBadgesPromise])
.then((promiseResults) => {
if ((promiseResults[0].status === 'fulfilled') && (promiseResults[1].status ==='fulfilled')) {
let result = promiseResults[0].value;
result.badges = [];
// Iterate through the badges checking if this member has the badge
if (promiseResults[1].value) {
promiseResults[1].value.forEach(badge => {
if (badge.members.includes(member._id)) {
result.badges.push(badge.title);
}
});
}
return result;
}
else {
return null;
}
})
}
else {
return null;
}
})
.catch((error) => {
console.error(error);
return null;
});
return Promise.allSettled([validateRequestPromise, getMemberPromise])
.then((promiseResults) => {
return processPromiseResults(promiseResults);
})
}
// Returns an array of members indexed by 'username' and 'display_name'
// Request data parameters:
// limit (optional) the limit to be used in each query. Defaults to 50.
// display_name_property (optional) the member property to be used for the display name.
// Typically either 'name' (the default) or 'nickname'.
export async function post_getMemberNames(request) {
const data = await request.body.json();
const displayNameProperty = data.display_name_property ?? 'name';
const options = {
"suppressAuth": true,
"suppressHooks": true
};
const defaultLimit = 50;
let memberNames = [];
let limit = defaultLimit;
if (data.limit !== undefined) {
limit = parseInt(data.limit, 10);
if (isNaN(limit) || (limit <= 0)) {
limit =defaultLimit;
}
}
function extractMemberNames(items) {
let result = [];
items.forEach(function(item) {
result.push({
username: item.loginEmail,
display_name: ((item[displayNameProperty] === undefined) ||
(item[displayNameProperty] === null) ||
(item[displayNameProperty] === '')) ? item.loginEmail : item[displayNameProperty]
});
});
return result;
}
const validateRequestPromise = validateRequest(request, data);
const getMemberNamesPromise = wixData.query("Members/PrivateMembersData")
.limit(limit)
.find(options)
.then(async (results) => {
memberNames = memberNames.concat(extractMemberNames(results.items));
while (results.hasNext()) {
results = await results.next();
memberNames = memberNames.concat(extractMemberNames(results.items));
}
})
.catch((error) => {
console.error(error);
})
.then(() => {
return memberNames;
})
return Promise.allSettled([validateRequestPromise, getMemberNamesPromise])
.then((promiseResults) => {
return processPromiseResults(promiseResults);
})
}