mirror of
				https://github.com/therootcompany/greenlock-express.js.git
				synced 2025-11-03 21:42:47 +00:00 
			
		
		
		
	v3.0.1: http-01 and other bugfixes, update deps
This commit is contained in:
		
							parent
							
								
									3f437c6ebb
								
							
						
					
					
						commit
						405e98620c
					
				
							
								
								
									
										8
									
								
								demo.js
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								demo.js
									
									
									
									
									
								
							@ -14,14 +14,8 @@ function initialize() {
 | 
				
			|||||||
		staging: true,
 | 
							staging: true,
 | 
				
			||||||
		cluster: true,
 | 
							cluster: true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		challenges: {
 | 
					 | 
				
			||||||
			"dns-01": {
 | 
					 | 
				
			||||||
				module: "acme-dns-01-digitalocean"
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		notify: function(ev, params) {
 | 
							notify: function(ev, params) {
 | 
				
			||||||
			console.log(ev, params);
 | 
								console.info(ev, params);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	return config;
 | 
						return config;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										68
									
								
								greenlock.js
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								greenlock.js
									
									
									
									
									
								
							@ -9,33 +9,49 @@ module.exports.create = function(opts) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// TODO move to greenlock proper
 | 
						// TODO move to greenlock proper
 | 
				
			||||||
	greenlock.getAcmeHttp01ChallengeResponse = function(opts) {
 | 
						greenlock.getAcmeHttp01ChallengeResponse = function(opts) {
 | 
				
			||||||
		return greenlock.find({ servername: opts.servername }).then(function(sites) {
 | 
							// TODO some sort of caching to prevent database hits?
 | 
				
			||||||
			if (!sites.length) {
 | 
							return greenlock
 | 
				
			||||||
				return null;
 | 
								._config({ servername: opts.servername })
 | 
				
			||||||
			}
 | 
								.then(function(site) {
 | 
				
			||||||
			var site = sites[0];
 | 
									if (!site) {
 | 
				
			||||||
			if (!site.challenges || !site.challenges["http-01"]) {
 | 
										return null;
 | 
				
			||||||
				return null;
 | 
									}
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var plugin;
 | 
									// Hmm... this _should_ be impossible
 | 
				
			||||||
			try {
 | 
									if (!site.challenges || !site.challenges["http-01"]) {
 | 
				
			||||||
				plugin = require(site.challenges["http-01"].module);
 | 
										return null;
 | 
				
			||||||
				plugin = plugin.create(site.challenges["http-01"]);
 | 
									}
 | 
				
			||||||
			} catch (e) {
 | 
					 | 
				
			||||||
				console.error("error getting acme http-01 plugin");
 | 
					 | 
				
			||||||
				console.error(e);
 | 
					 | 
				
			||||||
				return null;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return plugin.get(opts).then(function(result) {
 | 
									return Greenlock._loadChallenge(site.challenges, "http-01");
 | 
				
			||||||
				// TODO is this the right way?
 | 
								})
 | 
				
			||||||
				var ch = (result && result.challenge) || result || {};
 | 
								.then(function(plugin) {
 | 
				
			||||||
				return {
 | 
									return plugin
 | 
				
			||||||
					keyAuthorization: ch.keyAuthorization
 | 
										.get({
 | 
				
			||||||
				};
 | 
											challenge: {
 | 
				
			||||||
 | 
												type: opts.type,
 | 
				
			||||||
 | 
												//hostname: opts.servername,
 | 
				
			||||||
 | 
												altname: opts.servername,
 | 
				
			||||||
 | 
												identifier: { value: opts.servername },
 | 
				
			||||||
 | 
												token: opts.token
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
										.then(function(result) {
 | 
				
			||||||
 | 
											var keyAuth;
 | 
				
			||||||
 | 
											if (result) {
 | 
				
			||||||
 | 
												// backwards compat that shouldn't be dropped
 | 
				
			||||||
 | 
												// because new v3 modules had to do this to be
 | 
				
			||||||
 | 
												// backwards compatible with Greenlock v2.7 at
 | 
				
			||||||
 | 
												// the time.
 | 
				
			||||||
 | 
												if (result.challenge) {
 | 
				
			||||||
 | 
													result = challenge;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												keyAuth = result.keyAuthorization;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											return {
 | 
				
			||||||
 | 
												keyAuthorization: keyAuth
 | 
				
			||||||
 | 
											};
 | 
				
			||||||
 | 
										});
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return greenlock;
 | 
						return greenlock;
 | 
				
			||||||
@ -43,9 +59,9 @@ module.exports.create = function(opts) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function addGreenlockAgent(opts) {
 | 
					function addGreenlockAgent(opts) {
 | 
				
			||||||
	// Add greenlock as part of Agent, unless this is greenlock
 | 
						// Add greenlock as part of Agent, unless this is greenlock
 | 
				
			||||||
	if (!/^greenlock(-express|-pro)?/.test(opts.packageAgent)) {
 | 
						if (!/greenlock(-express|-pro)?/i.test(opts.packageAgent)) {
 | 
				
			||||||
		var pkg = require("./package.json");
 | 
							var pkg = require("./package.json");
 | 
				
			||||||
		var packageAgent = pkg.name + "/" + pkg.version;
 | 
							var packageAgent = "Greenlock_Express/" + pkg.version;
 | 
				
			||||||
		opts.packageAgent += " " + packageAgent;
 | 
							opts.packageAgent += " " + packageAgent;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -23,11 +23,15 @@ HttpMiddleware.create = function(gl, defaultApp) {
 | 
				
			|||||||
		var token = req.url.slice(challengePrefix.length);
 | 
							var token = req.url.slice(challengePrefix.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token })
 | 
							gl.getAcmeHttp01ChallengeResponse({ type: "http-01", servername: hostname, token: token })
 | 
				
			||||||
			.then(function(result) {
 | 
					 | 
				
			||||||
				respondWithGrace(res, result, hostname, token);
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			.catch(function(err) {
 | 
								.catch(function(err) {
 | 
				
			||||||
				respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname);
 | 
									respondToError(gl, res, err, "http_01_middleware_challenge_response", hostname);
 | 
				
			||||||
 | 
									return { __done: true };
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								.then(function(result) {
 | 
				
			||||||
 | 
									if (result && result.__done) {
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return respondWithGrace(res, result, hostname, token);
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -75,7 +75,7 @@ Master._spawnWorkers = function(opts, greenlock) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cluster.on("exit", function() {
 | 
						cluster.once("exit", function() {
 | 
				
			||||||
		setTimeout(function() {
 | 
							setTimeout(function() {
 | 
				
			||||||
			process.exit(3);
 | 
								process.exit(3);
 | 
				
			||||||
		}, 100);
 | 
							}, 100);
 | 
				
			||||||
@ -101,7 +101,7 @@ Master._spawnWorkers = function(opts, greenlock) {
 | 
				
			|||||||
Master._spawnWorker = function(opts, greenlock) {
 | 
					Master._spawnWorker = function(opts, greenlock) {
 | 
				
			||||||
	var w = cluster.fork();
 | 
						var w = cluster.fork();
 | 
				
			||||||
	// automatically added to master's `cluster.workers`
 | 
						// automatically added to master's `cluster.workers`
 | 
				
			||||||
	w.on("exit", function(code, signal) {
 | 
						w.once("exit", function(code, signal) {
 | 
				
			||||||
		// TODO handle failures
 | 
							// TODO handle failures
 | 
				
			||||||
		// Should test if the first starts successfully
 | 
							// Should test if the first starts successfully
 | 
				
			||||||
		// Should exit if failures happen too quickly
 | 
							// Should exit if failures happen too quickly
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										30
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -5,9 +5,9 @@
 | 
				
			|||||||
	"requires": true,
 | 
						"requires": true,
 | 
				
			||||||
	"dependencies": {
 | 
						"dependencies": {
 | 
				
			||||||
		"@root/acme": {
 | 
							"@root/acme": {
 | 
				
			||||||
			"version": "3.0.6",
 | 
								"version": "3.0.8",
 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.6.tgz",
 | 
								"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz",
 | 
				
			||||||
			"integrity": "sha512-KfgwcyWDsT90vz+gmWbCwuOBolwV5Gcg0WHsG8/dznDC7a6QF4AmZsil7mIWKGJxHdi6MElkyrHZyK53OhPnug==",
 | 
								"integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==",
 | 
				
			||||||
			"requires": {
 | 
								"requires": {
 | 
				
			||||||
				"@root/encoding": "^1.0.1",
 | 
									"@root/encoding": "^1.0.1",
 | 
				
			||||||
				"@root/keypairs": "^0.9.0",
 | 
									"@root/keypairs": "^0.9.0",
 | 
				
			||||||
@ -40,18 +40,18 @@
 | 
				
			|||||||
			"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ=="
 | 
								"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ=="
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"@root/greenlock": {
 | 
							"@root/greenlock": {
 | 
				
			||||||
			"version": "3.0.1",
 | 
								"version": "3.0.5",
 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.1.tgz",
 | 
								"resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.5.tgz",
 | 
				
			||||||
			"integrity": "sha512-Hyrnw/gXgmM4Ml7l0SAwYQ1FAq685dwRXpp7zmOxZDieUGWwP+GUcXOrEefph/lpELWJ5igcPzdEkIGtjMCTww==",
 | 
								"integrity": "sha512-2fjtMRel/BDnxOhlIukcxdLjZSwmTSswwBKG8jvTYWwXsXMP5ef1YOdHYR7Vn6gFltaku0gBdE3ecG4KsV+g3A==",
 | 
				
			||||||
			"requires": {
 | 
								"requires": {
 | 
				
			||||||
				"@root/acme": "^3.0.6",
 | 
									"@root/acme": "^3.0.8",
 | 
				
			||||||
				"@root/csr": "^0.8.1",
 | 
									"@root/csr": "^0.8.1",
 | 
				
			||||||
				"@root/keypairs": "^0.9.0",
 | 
									"@root/keypairs": "^0.9.0",
 | 
				
			||||||
				"@root/mkdirp": "^1.0.0",
 | 
									"@root/mkdirp": "^1.0.0",
 | 
				
			||||||
				"@root/request": "^1.3.10",
 | 
									"@root/request": "^1.3.10",
 | 
				
			||||||
				"acme-http-01-standalone": "^3.0.0",
 | 
									"acme-http-01-standalone": "^3.0.5",
 | 
				
			||||||
				"cert-info": "^1.5.1",
 | 
									"cert-info": "^1.5.1",
 | 
				
			||||||
				"greenlock-manager-fs": "^0.6.0",
 | 
									"greenlock-manager-fs": "^0.6.2",
 | 
				
			||||||
				"greenlock-store-fs": "^3.2.0",
 | 
									"greenlock-store-fs": "^3.2.0",
 | 
				
			||||||
				"safe-replace": "^1.1.0"
 | 
									"safe-replace": "^1.1.0"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -91,9 +91,9 @@
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"acme-http-01-standalone": {
 | 
							"acme-http-01-standalone": {
 | 
				
			||||||
			"version": "3.0.0",
 | 
								"version": "3.0.5",
 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.0.tgz",
 | 
								"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz",
 | 
				
			||||||
			"integrity": "sha512-lZqVab2UZ1Dp36HemfhGEvdYOcVNg5wyVXNjtPUqGSAOVUOKqwi3gDrTGwqz+FBrEEEEpTngDPaZn2g3hfmPLA=="
 | 
								"integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg=="
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"cert-info": {
 | 
							"cert-info": {
 | 
				
			||||||
			"version": "1.5.1",
 | 
								"version": "1.5.1",
 | 
				
			||||||
@ -106,9 +106,9 @@
 | 
				
			|||||||
			"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
 | 
								"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"greenlock-manager-fs": {
 | 
							"greenlock-manager-fs": {
 | 
				
			||||||
			"version": "0.6.0",
 | 
								"version": "0.6.2",
 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-0.6.0.tgz",
 | 
								"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-0.6.2.tgz",
 | 
				
			||||||
			"integrity": "sha512-o5RZ/T4j6eaUXCVnZ2dScE1pAjFuS8/R4ZDn7mCyRkxBjZvXJU7TpYe5Bc/wmN8x+gLHqVUECZWC6VdA/DbShQ==",
 | 
								"integrity": "sha512-hfQvrOsbSBffAe4dcZL2Aju4XQi3ePlGvwHcxOnIpqdxR8o/5ePNYAyvqwPFPt5iryHvRr7aMrPaA2CO2u3X6g==",
 | 
				
			||||||
			"requires": {
 | 
								"requires": {
 | 
				
			||||||
				"@root/mkdirp": "^1.0.0",
 | 
									"@root/mkdirp": "^1.0.0",
 | 
				
			||||||
				"safe-replace": "^1.1.0"
 | 
									"safe-replace": "^1.1.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	"name": "@root/greenlock-express",
 | 
						"name": "@root/greenlock-express",
 | 
				
			||||||
	"version": "3.0.0",
 | 
						"version": "3.0.1",
 | 
				
			||||||
	"description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.",
 | 
						"description": "Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.",
 | 
				
			||||||
	"main": "greenlock-express.js",
 | 
						"main": "greenlock-express.js",
 | 
				
			||||||
	"homepage": "https://greenlock.domains",
 | 
						"homepage": "https://greenlock.domains",
 | 
				
			||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
		"example": "examples"
 | 
							"example": "examples"
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	"dependencies": {
 | 
						"dependencies": {
 | 
				
			||||||
		"@root/greenlock": "^3.0.1",
 | 
							"@root/greenlock": "^3.0.5",
 | 
				
			||||||
		"redirect-https": "^1.1.5"
 | 
							"redirect-https": "^1.1.5"
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	"trulyOptionalDependencies": {
 | 
						"trulyOptionalDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								sni.js
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								sni.js
									
									
									
									
									
								
							@ -118,26 +118,24 @@ sni.create = function(greenlock, secureOpts) {
 | 
				
			|||||||
			meta.refreshAt = Date.now() + randomRefreshOffset();
 | 
								meta.refreshAt = Date.now() + randomRefreshOffset();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO greenlock.get({ servername: servername })
 | 
					 | 
				
			||||||
		// TODO don't get unknown certs at all, rely on auto-updates from greenlock
 | 
							// TODO don't get unknown certs at all, rely on auto-updates from greenlock
 | 
				
			||||||
		// Note: greenlock.renew() will return an existing fresh cert or issue a new one
 | 
							// Note: greenlock.get() will return an existing fresh cert or issue a new one
 | 
				
			||||||
		return greenlock.renew({ servername: servername }).then(function(matches) {
 | 
							return greenlock.get({ servername: servername }).then(function(result) {
 | 
				
			||||||
			var meta = getCachedMeta(servername);
 | 
								var meta = getCachedMeta(servername);
 | 
				
			||||||
			if (!meta) {
 | 
								if (!meta) {
 | 
				
			||||||
				meta = _cache[servername] = { secureContext: {} };
 | 
									meta = _cache[servername] = { secureContext: { _valid: false } };
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// prevent from being punked by bot trolls
 | 
								// prevent from being punked by bot trolls
 | 
				
			||||||
			meta.refreshAt = Date.now() + smallStagger;
 | 
								meta.refreshAt = Date.now() + smallStagger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// nothing to do
 | 
								// nothing to do
 | 
				
			||||||
			if (!matches.length) {
 | 
								if (!result) {
 | 
				
			||||||
				return null;
 | 
									return null;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// we only care about the first one
 | 
								// we only care about the first one
 | 
				
			||||||
			var pems = matches[0].pems;
 | 
								var pems = result.pems;
 | 
				
			||||||
			var site = matches[0].site;
 | 
								var site = result.site;
 | 
				
			||||||
			var match = matches[0];
 | 
					 | 
				
			||||||
			if (!pems || !pems.cert) {
 | 
								if (!pems || !pems.cert) {
 | 
				
			||||||
				// nothing to do
 | 
									// nothing to do
 | 
				
			||||||
				// (and the error should have been reported already)
 | 
									// (and the error should have been reported already)
 | 
				
			||||||
@ -152,9 +150,10 @@ sni.create = function(greenlock, secureOpts) {
 | 
				
			|||||||
					cert: pems.cert + "\n" + pems.chain + "\n"
 | 
										cert: pems.cert + "\n" + pems.chain + "\n"
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
								meta.secureContext._valid = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// copy this same object into every place
 | 
								// copy this same object into every place
 | 
				
			||||||
			[match.altnames || site.altnames || [match.subject || site.subject]].forEach(function(altname) {
 | 
								(result.altnames || site.altnames || [result.subject || site.subject]).forEach(function(altname) {
 | 
				
			||||||
				_cache[altname] = meta;
 | 
									_cache[altname] = meta;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ var msgPrefix = "greenlock:";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Worker.create = function() {
 | 
					Worker.create = function() {
 | 
				
			||||||
	var greenlock = {};
 | 
						var greenlock = {};
 | 
				
			||||||
	["getAcmeHttp01ChallengeResponse", "renew", "notify"].forEach(function(k) {
 | 
						["getAcmeHttp01ChallengeResponse", "get", "notify"].forEach(function(k) {
 | 
				
			||||||
		greenlock[k] = function(args) {
 | 
							greenlock[k] = function(args) {
 | 
				
			||||||
			return rpc(k, args);
 | 
								return rpc(k, args);
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
@ -40,10 +40,13 @@ function rpc(funcname, msg) {
 | 
				
			|||||||
			if (msg._id !== id) {
 | 
								if (msg._id !== id) {
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								process.removeListener("message", getResponse);
 | 
				
			||||||
			clearTimeout(timeout);
 | 
								clearTimeout(timeout);
 | 
				
			||||||
			resolve(msg._result);
 | 
								resolve(msg._result);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// TODO keep a single listener than just responds
 | 
				
			||||||
 | 
							// via a collection of callbacks? or leave as is?
 | 
				
			||||||
		process.on("message", getResponse);
 | 
							process.on("message", getResponse);
 | 
				
			||||||
		process.send({
 | 
							process.send({
 | 
				
			||||||
			_id: id,
 | 
								_id: id,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user