UNPKG

@rnaga/wp-node

Version:

👉 **[View Full Documentation at rnaga.github.io/wp-node →](https://rnaga.github.io/wp-node/)**

207 lines (206 loc) • 8.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApplicationPasswordsUtil = void 0; const common_1 = require("../../common"); const config_1 = require("../../config"); const component_1 = require("../../decorators/component"); const transactions_1 = require("../../transactions"); const application_password_1 = require("../../validators/application-password"); const components_1 = require("../components"); const options_1 = require("../options"); const meta_util_1 = require("./meta.util"); const site_util_1 = require("./site.util"); const zod_1 = require("zod"); const user_util_1 = require("./user.util"); // Application Passwords should be 24 characters long. // https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#application-passwords const PW_LENGTH = 24; let ApplicationPasswordsUtil = class ApplicationPasswordsUtil { config; components; constructor(config, components) { this.config = config; this.components = components; } getMetaKey() { return "_application_passwords"; } getOptionsKey() { return "using_application_passwords"; } isAvailable(checkSsl = true) { return (this.config.config.useApplicationPasswords === true && (checkSsl === false || this.config.isSsl() === true)); } async isInUse() { const options = this.components.get(options_1.Options); const siteUtil = this.components.get(site_util_1.SiteUtil); const mainSiteId = await siteUtil.getMainSiteId(); const using = !this.config.isMultiSite() ? await options.get(this.getOptionsKey()) : await options.get(this.getOptionsKey(), { siteId: mainSiteId }); return (using === "1" || parseInt(`${using}`) === 1 || Boolean(`${using}`) === true); } // create_new_application_password async createNewPassword(userId, options) { const name = zod_1.z.string().min(2).max(100).parse(options.name); const newPassword = (0, common_1.generatePassword)(PW_LENGTH, false); const hashedPassword = (0, common_1.fastHash)(newPassword); const newItem = { uuid: (0, common_1.uuid4)(), app_id: options.app_id || "", name, password: hashedPassword, created: Math.floor(Date.now() / 1000), last_used: null, last_ip: null, }; // Set Option Key if (this.config.isMultiSite()) { const siteId = await this.components.get(site_util_1.SiteUtil).getMainSiteId(); const metaTrx = this.components.get(transactions_1.MetaTrx); await metaTrx.upsert("site", siteId, this.getOptionsKey(), "1"); } else { const optionsTrx = this.components.get(transactions_1.OptionsTrx); await optionsTrx.insert(this.getOptionsKey(), "1", { upsert: true }); } const passwords = await this.getUserPasswords(userId); passwords.push(newItem); const result = await this.setUserPasswords(userId, passwords); if (!result) { throw new Error("Failed to set user passwords"); } return { password: newPassword, item: newItem, }; } // record_application_password_usage async recordPasswordUsage(userId, uuid, options) { const passwords = await this.getUserPasswords(userId); for (const password of passwords) { if (password.uuid !== uuid) { continue; } const lastUsed = password.last_used || 0; // Only record activity once a day. if (lastUsed > 0 && lastUsed + 86400 > Math.floor(Date.now() / 1000)) { return true; } // Update the password object in the array password.last_used = Math.floor(Date.now() / 1000); password.last_ip = options.ip || null; // Save the updated passwords array return await this.setUserPasswords(userId, passwords); } return false; } // update_application_password async updatePasswordName(userId, uuid, newName) { const name = zod_1.z.string().min(2).max(100).parse(newName); const passwords = await this.getUserPasswords(userId); for (const password of passwords) { if (password.uuid !== uuid) { continue; } // Update the password object in the array password.name = name; // Save the updated passwords array return await this.setUserPasswords(userId, passwords); } return false; } // delete_application_password async deletePassword(userId, uuid) { const passwords = await this.getUserPasswords(userId); const filtered = passwords.filter((password) => password.uuid !== uuid); return await this.setUserPasswords(userId, filtered); } // delete_all_application_passwords async deleteAllPasswords(userId) { return await this.setUserPasswords(userId, []); } parsePasswords(passwords) { return zod_1.z.array(application_password_1.applicationPassword).parse(passwords || []); } // get_user_application_password async getUserPasswords(userId) { const metaUtil = this.components.get(meta_util_1.MetaUtil); const passwords = await metaUtil.getValue("user", userId, this.getMetaKey()); // Unserialize const serialized = (0, common_1.phpUnserialize)(passwords) || []; return this.parsePasswords(serialized); } // get_user_application_password async getUserPasswordByUuid(userId, uuid) { if (uuid.length !== 36) { return null; } const passwords = await this.getUserPasswords(userId); return passwords.find((password) => password.uuid === uuid) || null; } // set_user_application_passwords async setUserPasswords(userId, passwords) { const parsed = this.parsePasswords(passwords); const metaTrx = this.components.get(transactions_1.MetaTrx); return await metaTrx.upsert("user", userId, this.getMetaKey(), parsed, { serialize: true, }); } chunkPassword(password) { // Clean up first with cleanupPasswordHash const cleanedUp = (0, common_1.cleanupPasswordHash)(password); // trim( chunk_split( $raw_password, 4, ' ' ) ); return (cleanedUp .match(/.{1,4}/g) ?.join(" ") .trim() || ""); } // wp_authenticate_application_password async authenticate(userIdOrName, rawPassword, options) { if ((await this.isInUse()) === false) { return undefined; } // Get user const userUtil = this.components.get(user_util_1.UserUtil); const user = await userUtil.get(userIdOrName); if (!user.props) { return undefined; } const userId = user.props.ID; const password = (0, common_1.cleanupPasswordHash)(rawPassword); if (password.length !== PW_LENGTH) { return undefined; } // Get all password objects const passwords = await this.getUserPasswords(userId); for (const item of passwords) { if (item.password && (0, common_1.verifyFastHash)(password, item.password)) { // Record usage await this.recordPasswordUsage(userId, item.uuid, { ip: options?.ip || null, }); // Return user object return user; } } return undefined; } }; exports.ApplicationPasswordsUtil = ApplicationPasswordsUtil; exports.ApplicationPasswordsUtil = ApplicationPasswordsUtil = __decorate([ (0, component_1.component)(), __metadata("design:paramtypes", [config_1.Config, components_1.Components]) ], ApplicationPasswordsUtil);