chore: import verified syly2 maintenance baseline without embedded credentials
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
root="$PWD"
|
||||
mvn_bin="${MVN:-mvn}"
|
||||
repo="${MAVEN_REPO_LOCAL:-$root/.local/m2}"
|
||||
mkdir -p "$repo"
|
||||
install_jar() {
|
||||
"$mvn_bin" -B -ntp "-Dmaven.repo.local=$repo" \
|
||||
org.apache.maven.plugins:maven-install-plugin:3.1.4:install-file \
|
||||
"-DgroupId=$1" "-DartifactId=$2" "-Dversion=$3" \
|
||||
-Dpackaging=jar -DgeneratePom=true "-Dfile=$4"
|
||||
}
|
||||
install_jar com.oracle ojdbc14 10.2.0.4.0 jar/ojdbc14/ojdbc14/10.2.0.4.0/ojdbc14-10.2.0.4.0.jar
|
||||
for name in CKFinder-updateByAlexander CKFinderPlugin-FileEditor CKFinderPlugin-ImageResize CKFinderPlugin-Watermark; do
|
||||
install_jar com.ckfinder "$name" 2.4 "jar/ckfinder/ckfinder/$name/2.4/$name-2.4.jar"
|
||||
done
|
||||
install_jar com.artofsolving jodconverter 3.0-beta-4 src/main/webapp/WEB-INF/lib/jodconverter-3.0-beta-4.jar
|
||||
"$mvn_bin" -B -ntp "-Dmaven.repo.local=$repo" -Dmaven.test.skip=true clean package
|
||||
@@ -0,0 +1,49 @@
|
||||
import com.zzc.core.util.EncryptionUtil;
|
||||
import com.zzc.core.util.RsaUtils;
|
||||
import com.zzc.core.util.RuntimeSecrets;
|
||||
import cn.hutool.crypto.asymmetric.KeyType;
|
||||
import cn.hutool.crypto.asymmetric.RSA;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
/** Offline checks; the caller supplies test keys in a private temporary file. */
|
||||
public class SecretsCheck {
|
||||
private static void check(boolean result, String message) {
|
||||
if (!result) throw new AssertionError(message);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length > 0 && args[0].equals("config")) {
|
||||
check(args[1].equals(RuntimeSecrets.required("SYLY_CONFIG_TEST")), "Configuration source/precedence");
|
||||
System.out.println("Private-file/environment configuration checks passed");
|
||||
return;
|
||||
}
|
||||
if (args.length > 0 && args[0].equals("missing")) {
|
||||
try {
|
||||
RuntimeSecrets.required("SYLY_MISSING_TEST_SECRET");
|
||||
throw new AssertionError("Missing secrets must fail");
|
||||
} catch (IllegalStateException expected) {
|
||||
check(!expected.getMessage().contains("test-secret-value"), "Value leaked");
|
||||
}
|
||||
check(RuntimeSecrets.optional("SYLY_MISSING_TEST_SECRET").isEmpty(), "Optional default");
|
||||
System.out.println("Missing-secret checks passed");
|
||||
return;
|
||||
}
|
||||
String plain = "offline-check-中文-2026";
|
||||
String encrypted = EncryptionUtil.encrypt(plain);
|
||||
check(!plain.equals(encrypted), "AES must encrypt");
|
||||
check(plain.equals(EncryptionUtil.decrypt(encrypted)), "AES round trip");
|
||||
String raw = SecureUtil.aes(Base64.getDecoder().decode(RuntimeSecrets.required("SYLY_AES_KEY"))).encryptBase64(plain);
|
||||
check(encrypted.substring(8).equals(raw), "AES format changed");
|
||||
check(plain.equals(EncryptionUtil.decrypt(raw)), "Legacy ciphertext without prefix");
|
||||
check(EncryptionUtil.encrypt(null) == null, "Null input");
|
||||
check("".equals(EncryptionUtil.decrypt("")), "Empty input");
|
||||
check(plain.equals(EncryptionUtil.decrypt(plain)), "Plaintext compatibility");
|
||||
String rsaCipher = RsaUtils.getInstance().encrypt(plain);
|
||||
check(plain.equals(RsaUtils.decrypt(rsaCipher)), "RSA round trip with retained public key");
|
||||
RSA independent = new RSA(RuntimeSecrets.required("SYLY_RSA_PRIVATE_KEY"), RsaUtils.getPublicKey());
|
||||
check(plain.equals(new String(independent.decrypt(Base64.getDecoder().decode(rsaCipher), KeyType.PrivateKey), StandardCharsets.UTF_8)), "RSA compatibility");
|
||||
System.out.println("AES/RSA offline compatibility checks passed");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Inspect the built WAR without launching the application or reading business data."""
|
||||
from pathlib import Path
|
||||
import collections
|
||||
import hashlib
|
||||
import json
|
||||
import struct
|
||||
import zipfile
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
war = root / 'target/syly.war'
|
||||
required = [
|
||||
'WEB-INF/web.xml',
|
||||
'WEB-INF/classes/com/zzc/web/system/controller/core/LoginController.class',
|
||||
'WEB-INF/classes/com/zzc/core/interceptors/AuthInterceptor.class',
|
||||
'WEB-INF/classes/com/zzc/web/htoal/controller/HotelMonthlyController.class',
|
||||
'WEB-INF/classes/com/zzc/core/util/RuntimeSecrets.class',
|
||||
]
|
||||
with zipfile.ZipFile(war) as archive:
|
||||
assert archive.testzip() is None, 'WAR CRC failure'
|
||||
names = archive.namelist()
|
||||
assert all(name in names for name in required), 'Missing application entry'
|
||||
classes = [n for n in names if n.startswith('WEB-INF/classes/') and n.endswith('.class')]
|
||||
versions = collections.Counter(struct.unpack('>H', archive.read(n)[6:8])[0] for n in classes)
|
||||
assert set(versions) == {52}, versions
|
||||
libs = [n for n in names if n.startswith('WEB-INF/lib/') and n.endswith('.jar')]
|
||||
for name in ['dbconfig.properties', 'sysConfig.properties', 'zzc/zzc_database.properties']:
|
||||
data = archive.read('WEB-INF/classes/' + name).decode('utf-8')
|
||||
for line in data.splitlines():
|
||||
if line.startswith(('jdbc.password=', 'mail.pwd=', 'password=')):
|
||||
assert not line.split('=', 1)[1].strip(), 'Packaged credential in ' + name
|
||||
assert 'druidStatView' not in archive.read('WEB-INF/web.xml').decode('utf-8')
|
||||
print(json.dumps({
|
||||
'war_sha256': hashlib.sha256(war.read_bytes()).hexdigest(),
|
||||
'war_bytes': war.stat().st_size,
|
||||
'zip_crc_check': 'passed',
|
||||
'compiled_class_files': len(classes),
|
||||
'class_major_versions': dict(versions),
|
||||
'bundled_jars': len(libs),
|
||||
'required_entries_present': required,
|
||||
'packaged_credential_checks': 'passed',
|
||||
}, indent=2))
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
mkdir -p target/offline-checks
|
||||
jdk_bin="${JAVA_HOME:?Set JAVA_HOME to JDK 8}/bin"
|
||||
cp="target/classes:target/syly/WEB-INF/lib/*"
|
||||
"$jdk_bin/javac" -encoding UTF-8 -cp "$cp" -d target/offline-checks scripts/verification/SecretsCheck.java
|
||||
"$jdk_bin/java" -cp "target/offline-checks:$cp" SecretsCheck missing
|
||||
printf 'SYLY_CONFIG_TEST=from-file\n' > target/offline-checks/config-test.properties
|
||||
env -u SYLY_CONFIG_TEST "$jdk_bin/java" -Dsyly.secrets.file="$PWD/target/offline-checks/config-test.properties" -cp "target/offline-checks:$cp" SecretsCheck config from-file
|
||||
SYLY_CONFIG_TEST=from-environment "$jdk_bin/java" -Dsyly.secrets.file="$PWD/target/offline-checks/config-test.properties" -cp "target/offline-checks:$cp" SecretsCheck config from-environment
|
||||
# Uses the existing deployment keys supplied privately by the operator.
|
||||
"$jdk_bin/java" -cp "target/offline-checks:$cp" SecretsCheck
|
||||
Reference in New Issue
Block a user