403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /opt/push-server/lib/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /opt/push-server/lib/license.js
const MySql = require("./storages/mysql");
const superAgent = require("superagent");
const crypto = require("crypto");
const config = require("../config");
const logger = require("./debug");
const { RegisterRequest, Notification, License } = require("./models");
let application = null;

const cache = new Map();
const cacheTtl = 3600 * 24 * 1000;
const dateTimePattern = /^(20[0-9]{2})-([0-9]{2})-([0-9]{2})$/;

//Let's extend License class with static methods.

/**
 *
 * @param {string} clientId
 * @param {string} host
 * @param useCache
 * @return Promise<null|License>
 */
License.get = function(clientId, host, useCache = true)
{
	if (typeof(clientId) !== "string" || clientId.length < 32)
	{
		return Promise.resolve(null);
	}

	if (typeof(host) !== "string" || host.length > 32)
	{
		return Promise.resolve(null);
	}

	let license = undefined;
	if (useCache)
	{
		const clientHosts = cache.get(clientId);
		const cacheRecord = clientHosts && clientHosts.get(host);
		if (typeof(cacheRecord) === 'object' && cacheRecord.expiry > Date.now())
		{
			license = cacheRecord.license;
		}
	}

	if (license !== undefined)
	{
		return Promise.resolve(license);
	}

	return new Promise(resolve => {
		MySql.getDatabase().then(db => {
			if (db === null)
			{
				resolve(null);
				return;
			}

			db.query("SELECT * FROM licenses WHERE clientId = ? AND host = ?", [clientId, host], (error, results) => {
				if (error)
				{
					logger.systemError(error);
					resolve(null);
				}
				else
				{
					const license = results && results[0] ? License.create(results[0]) : null;
					if (license !== null)
					{
						let clientHosts = cache.get(clientId);
						if (!clientHosts)
						{
							clientHosts = new Map();
							cache.set(clientId, clientHosts);
						}

						clientHosts.set(
							host,
							{
								license,
								expiry: Date.now() + cacheTtl
							}
						);
					}

					resolve(license);
				}
			});
		});

	});
};

/**
 *
 * @param {IncomingMessage} request
 * @returns {Promise<null|License>}
 */
License.getByRequest = function(request)
{
	const searchQuery = request.url.split('?');
	const urlSearchParams = new URLSearchParams(typeof(searchQuery[1]) === "string" ? searchQuery[1] : "");
	const clientId = urlSearchParams.get("clientId");

	const url = new URL(request.url, `https://${request.headers.host}`);
	const host = url.hostname;

	return License.get(clientId, host);
}

/**
 *
 * @param {RegisterRequest} registerRequest
 * @param {function(Error, License)} callback
 */
License.register = function(registerRequest, callback)
{
	superAgent
		.post(config.licenseServer)
		.send(registerRequest.verificationQuery)
		.retry(2)
		.timeout({
			response: 5000,
			deadline: 10000
		})
		.then(response => {

			const body = response.body || {};
			const result = body.result && typeof(body.result) === "object" ? body.result : null;

			if (body.status === "ok" && result)
			{
				const license = License.create({
					clientId: result["LICENSE_KEY_HEAD"],
					active: result["ACTIVE"],
					dateTo: result["DATE_TO"],
					siteUrl: result["SITE_URL"],
					host: registerRequest.host,
					verificationQuery: registerRequest.verificationQuery
				});

				License.save(license, callback);
			}
			else
			{
				const error = body.status === "error" && body.text ? body.text : "Unknown Error";

				callback(new Error(error), null);
			}

		})
		.catch(error => {
			callback(error, null);
		})
	;
};

/**
 *
 * @param {string} clientId
 * @param host
 * @param {function(Error, License)} callback
 */
License.unregister = function(clientId, host, callback)
{
	if (typeof(clientId) !== "string" || !clientId.match(/[a-z0-9]{32}/))
	{
		callback(new Error("Wrong Client Id."), null);
		return;
	}

	License.refresh(clientId);

	License.get(clientId, host, false).then(async (license) => {
		if (license === null)
		{
			callback(new Error("Client not found."), null);
			return;
		}

		const db = await MySql.getDatabase();
		if (!db)
		{
			callback(new Error("Couldn't connect to the database."), null);
			return;
		}

		db.query(`DELETE FROM licenses WHERE clientId = ? AND host = ?`, [clientId, host], (error) => {
			if (error)
			{
				callback(error, null);
				return;
			}

			if (application === null)
			{
				application = require("./application");
			}

			application.getAdapter().postIpcNotification(Notification.create({
				ipcLicenses: {
					licenses: [{
						license,
						action: "unregister"
					}]
				}
			}));

			callback(null, license);
		});
	});
};

/**
 *
 * @param {License} license
 * @param {function(Error, License)} callback
 */
License.save = function(license, callback)
{
	license = license && typeof(license) === "object" ? license : {};

	const clientId = typeof (license.clientId) === "string" ? license.clientId : "";
	if (!clientId.match(/[a-z0-9]{32}/))
	{
		callback(new Error("Wrong Client ID."), null);
		return;
	}

	const host = typeof(license.host) === "string" ? license.host : "";
	if (host.length < 2 || host.length > 32)
	{
		callback(new Error("Wrong hostname."), null);
		return;
	}

	const securityKey = this.getSecurityKey(clientId, host);

	let dateTo = typeof(license.dateTo) === "string" ? license.dateTo : "";
	const result = dateTimePattern.exec(dateTo);
	if (result === null)
	{
		callback(new Error("Wrong expiry date."), null);
		return;
	}

	dateTo = (new Date(dateTo)).getTime();

	const siteUrl = typeof(license.siteUrl) === "string" ? license.siteUrl.substr(0, 100) : "";

	const verificationQuery = typeof(license.verificationQuery) === "string" ? license.verificationQuery : "";
	if (verificationQuery.length < 64 || verificationQuery.length > 200)
	{
		callback(new Error("Wrong Verification Query."), null);
		return;
	}

	const sql = `
		INSERT INTO licenses (clientId, host, securityKey, dateTo, siteUrl, verificationQuery)
		VALUES (?, ?, ?, ?, ?, ?)
		ON DUPLICATE KEY UPDATE
			dateTo = values(dateTo),
			siteUrl = values(siteUrl),
			verificationQuery = values(verificationQuery)
	`;

	MySql.getDatabase().then((db) => {
		if (!db)
		{
			callback(new Error("Couldn't connect to the database."), null);
			return;
		}

		db.query(
			sql,
			[clientId, host, securityKey, dateTo, siteUrl, verificationQuery],
			(error) => {
				if (error)
				{
					callback(error, null);
				}
				else
				{
					License.refresh(clientId);

					License.get(clientId, host).then(license => {
						if (application === null)
						{
							application = require("./application");
						}

						application.getAdapter().postIpcNotification(Notification.create({
							ipcLicenses: {
								licenses: [{
									license,
									action: "register"
								}]
							}
						}));

						callback(null, license);
					});
				}
			}
		);
	});
};

License.getSecurityKey = function(clientId, host)
{
	let globalSecurityKey = null;
	if (
		config.security &&
		typeof (config.security.key) === "string" &&
		config.security.key.length >= 32 &&
		config.security.key.length <= 512
	)
	{
		globalSecurityKey = config.security.key;
	}

	const data = `push${clientId}${host}server`;

	let securityKey =
		globalSecurityKey === null
			? crypto.randomBytes(64).toString("hex")
			: crypto.createHmac("sha256", globalSecurityKey).update(data).digest("hex")
	;

	// Test Client Id
	if (clientId === "fd818684484258a5c6f0442a070661d6" && globalSecurityKey !== null)
	{
		securityKey = globalSecurityKey;
	}

	return securityKey;
}

/**
 *
 * @param {License} license
 */
License.isValid = function(license)
{
	if (license && license.clientId)
	{
		if (!Number.isInteger(license.dateTo))
		{
			return false;
		}

		const delta = license.dateTo - Date.now();
		if (delta > 0)
		{
			return true;
		}
		else
		{
			const oneDay = 3600 * 24 * 1000;
			const twoWeeks = 3600 * 24 * 14 * 1000;

			if (Number.isInteger(license.lastCheck) && (Date.now() - license.lastCheck) > oneDay)
			{
				void License.sync(license.clientId, license.host);
			}

			if (delta > -twoWeeks)
			{
				return true;
			}
		}
	}

	return false;
};

const syncLicenses = new Set();

License.sync = async function(clientId, host)
{
	if (syncLicenses.has(clientId))
	{
		return;
	}

	syncLicenses.add(clientId);

	const license = await License.get(clientId, host, false);
	const oneDay = 3600 * 24 * 1000;

	if (license === null || (Date.now() - license.lastCheck) < oneDay)
	{
		syncLicenses.delete(clientId);
		return;
	}

	const db = await MySql.getDatabase();
	if (!db)
	{
		syncLicenses.delete(clientId);
		return;
	}

	db.query(
		'UPDATE licenses SET lastCheck = ? WHERE clientId = ?',
		[Date.now(), clientId],
		error => {
			syncLicenses.delete(clientId);

			if (error)
			{
				logger.systemError("License refresh failed.", error);
				return;
			}

			license.lastCheck = Date.now();

			const registerRequest = RegisterRequest.create({
				verificationQuery: license.verificationQuery,
				host: host
			});

			License.register(registerRequest, (error, /*License*/license) => {
				if (error)
				{
					logger.systemError("License refresh failed.", error);
				}
			});
		}
	);
};

License.refresh = function(clientId)
{
	cache.delete(clientId);
	syncLicenses.delete(clientId);
};

module.exports = License;

Youez - 2016 - github.com/yon3zu
LinuXploit