mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[FEATURE] LauncherTrustManager и базовые сертификаты
This commit is contained in:
parent
8a52340b1a
commit
5a2aedbe06
10 changed files with 233 additions and 18 deletions
|
@ -13,6 +13,7 @@
|
|||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
|
@ -274,14 +275,16 @@ public static class LaunchServerDirectories
|
|||
public Path updatesDir;
|
||||
public Path profilesDir;
|
||||
public Path dir;
|
||||
public Path trustStore;
|
||||
public void collect()
|
||||
{
|
||||
if(updatesDir == null) updatesDir = dir.resolve("updates");
|
||||
if(profilesDir == null) profilesDir = dir.resolve("profiles");
|
||||
if(trustStore == null) trustStore = dir.resolve("truststore");
|
||||
}
|
||||
}
|
||||
|
||||
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, ECPublicKey publicKey, ECPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException {
|
||||
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, ECPublicKey publicKey, ECPrivateKey privateKey, CommandHandler commandHandler, CertificateManager certificateManager) throws IOException {
|
||||
this.dir = directories.dir;
|
||||
this.env = env;
|
||||
this.config = config;
|
||||
|
@ -293,6 +296,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
this.privateKey = privateKey;
|
||||
this.commandHandler = commandHandler;
|
||||
this.runtime = runtimeConfig;
|
||||
this.certificateManager = certificateManager;
|
||||
taskPool = new Timer("Timered task worker thread", true);
|
||||
launcherLibraries = dir.resolve("launcher-libraries");
|
||||
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
||||
|
@ -331,7 +335,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
reconfigurableManager = new ReconfigurableManager();
|
||||
authHookManager = new AuthHookManager();
|
||||
configManager = new ConfigManager();
|
||||
certificateManager = new CertificateManager();
|
||||
//Generate or set new Certificate API
|
||||
certificateManager.orgName = config.projectName;
|
||||
if(config.certificate != null && config.certificate.enabled)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.utils.command.CommandHandler;
|
||||
|
||||
|
@ -20,6 +21,7 @@ public class LaunchServerBuilder {
|
|||
private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||
private ECPublicKey publicKey;
|
||||
private ECPrivateKey privateKey;
|
||||
private CertificateManager certificateManager;
|
||||
private LaunchServer.LaunchServerConfigManager launchServerConfigManager;
|
||||
|
||||
public LaunchServerBuilder setConfig(LaunchServerConfig config) {
|
||||
|
@ -101,6 +103,11 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
|||
}
|
||||
};
|
||||
}
|
||||
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler);
|
||||
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler, certificateManager);
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setCertificateManager(CertificateManager certificateManager) {
|
||||
this.certificateManager = certificateManager;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import java.security.KeyPair;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
|
||||
|
@ -27,6 +28,7 @@
|
|||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.WebSocketService;
|
||||
|
@ -37,12 +39,12 @@
|
|||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class LaunchServerStarter {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
JVMHelper.checkStackTrace(LaunchServerStarter.class);
|
||||
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
||||
LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
||||
|
@ -52,18 +54,24 @@ public static void main(String[] args) throws Exception {
|
|||
LogHelper.error("StarterAgent is not started!");
|
||||
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
||||
}
|
||||
|
||||
Path dir = IOHelper.WORKING_DIR;
|
||||
Path configFile, runtimeConfigFile;
|
||||
Path publicKeyFile =dir.resolve("public.key");
|
||||
Path privateKeyFile = dir.resolve("private.key");
|
||||
ECPublicKey publicKey;
|
||||
ECPrivateKey privateKey;
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
CertificateManager certificateManager = new CertificateManager();
|
||||
try {
|
||||
certificateManager.readTrustStore(dir.resolve("truststore"));
|
||||
} catch (CertificateException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
LaunchServerRuntimeConfig runtimeConfig;
|
||||
LaunchServerConfig config;
|
||||
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"));
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"), certificateManager.trustManager);
|
||||
modulesManager.autoload();
|
||||
modulesManager.initModules(null);
|
||||
registerAll();
|
||||
|
@ -173,6 +181,7 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOExcept
|
|||
.setConfig(config)
|
||||
.setModulesManager(modulesManager)
|
||||
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||
.setCertificateManager(certificateManager)
|
||||
.build();
|
||||
server.run();
|
||||
}
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
package pro.gravit.launchserver.manangers;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
|
@ -43,6 +49,7 @@
|
|||
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||
|
||||
public class CertificateManager {
|
||||
public X509CertificateHolder ca;
|
||||
|
@ -51,9 +58,7 @@ public class CertificateManager {
|
|||
public X509CertificateHolder server;
|
||||
public AsymmetricKeyParameter serverKey;
|
||||
|
||||
|
||||
//public X509CertificateHolder server;
|
||||
//public AsymmetricKeyParameter serverKey;
|
||||
public LauncherTrustManager trustManager;
|
||||
|
||||
public int validDays = 60;
|
||||
public int minusHours = 6;
|
||||
|
@ -172,4 +177,34 @@ public X509CertificateHolder readCertificate(Reader reader) throws IOException {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void readTrustStore(Path dir) throws IOException, CertificateException {
|
||||
if(!IOHelper.isDir(dir))
|
||||
{
|
||||
Files.createDirectories(dir);
|
||||
try(OutputStream outputStream = IOHelper.newOutput(dir.resolve("GravitCentralRootCA.crt"));
|
||||
InputStream inputStream = IOHelper.newInput(IOHelper.getResourceURL("pro/gravit/launchserver/defaults/GravitCentralRootCA.crt")))
|
||||
{
|
||||
IOHelper.transfer(inputStream, outputStream);
|
||||
}
|
||||
}
|
||||
List<X509Certificate> certificates = new ArrayList<>();
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
IOHelper.walk(dir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if(file.toFile().getName().endsWith(".crt"))
|
||||
{
|
||||
try(InputStream inputStream = IOHelper.newInput(file))
|
||||
{
|
||||
certificates.add((X509Certificate) certFactory.generateCertificate(inputStream));
|
||||
} catch (CertificateException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
}, false);
|
||||
trustManager = new LauncherTrustManager(certificates.toArray(new X509Certificate[0]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||
|
||||
public class LaunchServerModulesManager extends SimpleModuleManager {
|
||||
public LaunchServerCoreModule coreModule;
|
||||
public LaunchServerModulesManager(Path modulesDir, Path configDir) {
|
||||
super(modulesDir, configDir);
|
||||
public LaunchServerModulesManager(Path modulesDir, Path configDir, LauncherTrustManager trustManager) {
|
||||
super(modulesDir, configDir, trustManager);
|
||||
coreModule = new LaunchServerCoreModule();
|
||||
modules.add(coreModule);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
|
@ -16,6 +16,7 @@
|
|||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.utils.command.StdCommandHandler;
|
||||
|
@ -32,7 +33,7 @@ public class StartLaunchServerTest {
|
|||
@BeforeAll
|
||||
public static void prepare() throws Exception
|
||||
{
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(modulesDir, configDir);
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(modulesDir, configDir, null);
|
||||
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
||||
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
|
@ -47,6 +48,7 @@ public static void prepare() throws Exception
|
|||
.setRuntimeConfig(runtimeConfig)
|
||||
.setPublicKey(publicKey)
|
||||
.setPrivateKey(privateKey)
|
||||
.setCertificateManager(new CertificateManager())
|
||||
.setLaunchServerConfigManager(new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -22,7 +28,9 @@
|
|||
import pro.gravit.utils.PublicURLClassLoader;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||
|
||||
public class SimpleModuleManager implements LauncherModulesManager {
|
||||
protected final List<LauncherModule> modules = new ArrayList<>();
|
||||
|
@ -30,6 +38,7 @@ public class SimpleModuleManager implements LauncherModulesManager {
|
|||
protected final SimpleModuleContext context;
|
||||
protected final ModulesConfigManager modulesConfigManager;
|
||||
protected final Path modulesDir;
|
||||
protected final LauncherTrustManager trustManager;
|
||||
protected LauncherInitContext initContext;
|
||||
|
||||
protected PublicURLClassLoader classLoader = new PublicURLClassLoader(new URL[]{});
|
||||
|
@ -113,6 +122,13 @@ public SimpleModuleManager(Path modulesDir, Path configDir) {
|
|||
modulesConfigManager = new SimpleModulesConfigManager(configDir);
|
||||
context = new SimpleModuleContext(this, modulesConfigManager);
|
||||
this.modulesDir = modulesDir;
|
||||
this.trustManager = null;
|
||||
}
|
||||
public SimpleModuleManager(Path modulesDir, Path configDir, LauncherTrustManager trustManager) {
|
||||
modulesConfigManager = new SimpleModulesConfigManager(configDir);
|
||||
context = new SimpleModuleContext(this, modulesConfigManager);
|
||||
this.modulesDir = modulesDir;
|
||||
this.trustManager = trustManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,7 +158,10 @@ public LauncherModule loadModule(Path file) throws IOException {
|
|||
return null;
|
||||
}
|
||||
classLoader.addURL(file.toUri().toURL());
|
||||
LauncherModule module = (LauncherModule) Class.forName(moduleClass, true, classLoader).newInstance();
|
||||
@SuppressWarnings("unchecked cast")
|
||||
Class<? extends LauncherModule> clazz = (Class<? extends LauncherModule>) Class.forName(moduleClass, false, classLoader);
|
||||
checkModuleClass(clazz);
|
||||
LauncherModule module = clazz.newInstance();
|
||||
loadModule(module);
|
||||
return module;
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
|
||||
|
@ -152,6 +171,23 @@ public LauncherModule loadModule(Path file) throws IOException {
|
|||
}
|
||||
}
|
||||
|
||||
protected void checkModuleClass(Class<? extends LauncherModule> clazz) throws SecurityException
|
||||
{
|
||||
if(trustManager == null) return;
|
||||
X509Certificate[] certificates = JVMHelper.getCertificates(clazz);
|
||||
if(certificates == null)
|
||||
{
|
||||
LogHelper.warning("Module class %s not signed", clazz.getName());
|
||||
}
|
||||
try {
|
||||
trustManager.checkCertificate(certificates, (c,s) -> {
|
||||
|
||||
});
|
||||
} catch (CertificateException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherModule getModule(String name) {
|
||||
for(LauncherModule module : modules)
|
||||
|
|
|
@ -114,7 +114,7 @@ public static URL[] getClassPathURL() {
|
|||
public static X509Certificate[] getCertificates(Class<?> clazz)
|
||||
{
|
||||
Object[] signers = clazz.getSigners();
|
||||
if(signers == null) return new X509Certificate[] {};
|
||||
if(signers == null) return null;
|
||||
return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package pro.gravit.utils.verify;
|
||||
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LauncherTrustManager {
|
||||
private final X509Certificate[] trustSigners;
|
||||
private final List<X509Certificate> trustCache = new ArrayList<>();
|
||||
|
||||
public LauncherTrustManager(X509Certificate[] trustSigners) {
|
||||
this.trustSigners = trustSigners;
|
||||
}
|
||||
public LauncherTrustManager(byte[][] encodedCertificate) throws CertificateException {
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
trustSigners = Arrays.stream(encodedCertificate).map((cert) -> {
|
||||
try(InputStream input = new ByteArrayInputStream(cert))
|
||||
{
|
||||
return (X509Certificate) certFactory.generateCertificate(input);
|
||||
} catch (IOException | CertificateException e) {
|
||||
LogHelper.error(e);
|
||||
return null;
|
||||
}
|
||||
}).toArray(X509Certificate[]::new);
|
||||
}
|
||||
public interface CertificateChecker
|
||||
{
|
||||
void check(X509Certificate cert, X509Certificate signer) throws CertificateException, SecurityException;
|
||||
}
|
||||
|
||||
public void checkCertificate(X509Certificate[] certs, CertificateChecker checker) throws CertificateException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
|
||||
if(certs == null) throw new SecurityException("Object not signed");
|
||||
for(int i=0;i< certs.length;++i)
|
||||
{
|
||||
X509Certificate cert = certs[i];
|
||||
if(trustCache.contains(cert))
|
||||
{
|
||||
//Добавляем в кеш все проверенные сертификаты
|
||||
for(int j=0;j < i;++j)
|
||||
trustCache.add(certs[j]);
|
||||
return;
|
||||
}
|
||||
X509Certificate signer = (i+1 < certs.length) ? certs[i+1] : null;
|
||||
cert.checkValidity();
|
||||
if(signer != null)
|
||||
{
|
||||
cert.verify(signer.getPublicKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!isTrusted(cert))
|
||||
{
|
||||
throw new CertificateException(String.format("Certificate %s is not signed by a trusted signer", cert.getSubjectDN().getName()));
|
||||
}
|
||||
}
|
||||
checker.check(cert, signer);
|
||||
}
|
||||
Collections.addAll(trustCache, certs);
|
||||
}
|
||||
public boolean isTrusted(X509Certificate certificate) throws CertificateEncodingException {
|
||||
//Java API не дает возможности вызвать getFingerprint
|
||||
//Oracle использует хак с кастом к sun.security.x509.X509CertImpl для проверки равенства сертификатов
|
||||
//Мы пойдем более медленным путем
|
||||
for(X509Certificate cert : trustSigners)
|
||||
{
|
||||
if(cert.getSerialNumber().equals(certificate.getSerialNumber()) //Проверка serialNumber (быстро)
|
||||
&& Arrays.equals(cert.getEncoded(), certificate.getEncoded())) //Полная проверка (медленно)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue