包含:登录失败锁定、90天密码有效期、30分钟会话超时、 强制改密、登录审计日志、屏幕水印、企业背景图、 备案信息固定底部、favicon、登录页JS修复等全部改动
This commit is contained in:
@@ -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);
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user