mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-01-10 00:06:51 +01:00
2270: clean up
This commit is contained in:
parent
dafe96b019
commit
39da4f1100
@ -0,0 +1,17 @@
|
|||||||
|
package stirling.software.SPDF.config.interfaces;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||||
|
import stirling.software.SPDF.utils.FileInfo;
|
||||||
|
|
||||||
|
public interface DatabaseInterface {
|
||||||
|
void exportDatabase() throws SQLException, UnsupportedProviderException;
|
||||||
|
|
||||||
|
void importDatabase();
|
||||||
|
|
||||||
|
boolean hasBackup();
|
||||||
|
|
||||||
|
List<FileInfo> getBackupList();
|
||||||
|
}
|
@ -1,49 +1,48 @@
|
|||||||
package stirling.software.SPDF.config.security;
|
package stirling.software.SPDF.config.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.sql.SQLException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.model.Role;
|
import stirling.software.SPDF.model.Role;
|
||||||
|
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Component
|
||||||
public class InitialSecuritySetup {
|
public class InitialSecuritySetup {
|
||||||
|
|
||||||
private final UserService userService;
|
@Autowired private UserService userService;
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
@Autowired private ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
private final DatabaseBackupInterface databaseBackupHelper;
|
@Autowired private DatabaseInterface databaseService;
|
||||||
|
|
||||||
public InitialSecuritySetup(
|
|
||||||
UserService userService,
|
|
||||||
ApplicationProperties applicationProperties,
|
|
||||||
DatabaseBackupInterface databaseBackupHelper) {
|
|
||||||
this.userService = userService;
|
|
||||||
this.applicationProperties = applicationProperties;
|
|
||||||
this.databaseBackupHelper = databaseBackupHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() throws IllegalArgumentException, IOException {
|
public void init() {
|
||||||
if (databaseBackupHelper.hasBackup() && !userService.hasUsers()) {
|
try {
|
||||||
databaseBackupHelper.importDatabase();
|
if (databaseService.hasBackup()) {
|
||||||
} else if (!userService.hasUsers()) {
|
databaseService.importDatabase();
|
||||||
initializeAdminUser();
|
}
|
||||||
} else {
|
|
||||||
databaseBackupHelper.exportDatabase();
|
if (!userService.hasUsers()) {
|
||||||
|
initializeAdminUser();
|
||||||
|
}
|
||||||
|
|
||||||
userService.migrateOauth2ToSSO();
|
userService.migrateOauth2ToSSO();
|
||||||
|
initializeInternalApiUser();
|
||||||
|
} catch (IllegalArgumentException | SQLException | UnsupportedProviderException e) {
|
||||||
|
log.error("Failed to initialize security setup.", e);
|
||||||
|
System.exit(1);
|
||||||
}
|
}
|
||||||
initializeInternalApiUser();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeAdminUser() throws IOException {
|
private void initializeAdminUser() throws SQLException, UnsupportedProviderException {
|
||||||
String initialUsername =
|
String initialUsername =
|
||||||
applicationProperties.getSecurity().getInitialLogin().getUsername();
|
applicationProperties.getSecurity().getInitialLogin().getUsername();
|
||||||
String initialPassword =
|
String initialPassword =
|
||||||
@ -52,36 +51,34 @@ public class InitialSecuritySetup {
|
|||||||
&& !initialUsername.isEmpty()
|
&& !initialUsername.isEmpty()
|
||||||
&& initialPassword != null
|
&& initialPassword != null
|
||||||
&& !initialPassword.isEmpty()
|
&& !initialPassword.isEmpty()
|
||||||
&& !userService.findByUsernameIgnoreCase(initialUsername).isPresent()) {
|
&& userService.findByUsernameIgnoreCase(initialUsername).isEmpty()) {
|
||||||
try {
|
|
||||||
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
|
userService.saveUser(initialUsername, initialPassword, Role.ADMIN.getRoleId());
|
||||||
log.info("Admin user created: " + initialUsername);
|
log.info("Admin user created: {}", initialUsername);
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
log.error("Failed to initialize security setup", e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
createDefaultAdminUser();
|
createDefaultAdminUser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createDefaultAdminUser() throws IllegalArgumentException, IOException {
|
private void createDefaultAdminUser() throws SQLException, UnsupportedProviderException {
|
||||||
String defaultUsername = "admin";
|
String defaultUsername = "admin";
|
||||||
String defaultPassword = "stirling";
|
String defaultPassword = "stirling";
|
||||||
if (!userService.findByUsernameIgnoreCase(defaultUsername).isPresent()) {
|
|
||||||
|
if (userService.findByUsernameIgnoreCase(defaultUsername).isEmpty()) {
|
||||||
userService.saveUser(defaultUsername, defaultPassword, Role.ADMIN.getRoleId(), true);
|
userService.saveUser(defaultUsername, defaultPassword, Role.ADMIN.getRoleId(), true);
|
||||||
log.info("Default admin user created: " + defaultUsername);
|
log.info("Default admin user created: {}", defaultUsername);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeInternalApiUser() throws IllegalArgumentException, IOException {
|
private void initializeInternalApiUser()
|
||||||
|
throws IllegalArgumentException, SQLException, UnsupportedProviderException {
|
||||||
if (!userService.usernameExistsIgnoreCase(Role.INTERNAL_API_USER.getRoleId())) {
|
if (!userService.usernameExistsIgnoreCase(Role.INTERNAL_API_USER.getRoleId())) {
|
||||||
userService.saveUser(
|
userService.saveUser(
|
||||||
Role.INTERNAL_API_USER.getRoleId(),
|
Role.INTERNAL_API_USER.getRoleId(),
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
Role.INTERNAL_API_USER.getRoleId());
|
Role.INTERNAL_API_USER.getRoleId());
|
||||||
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
|
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
|
||||||
log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
|
log.info("Internal API user created: {}", Role.INTERNAL_API_USER.getRoleId());
|
||||||
}
|
}
|
||||||
userService.syncCustomApiUser(applicationProperties.getSecurity().getCustomGlobalAPIKey());
|
userService.syncCustomApiUser(applicationProperties.getSecurity().getCustomGlobalAPIKey());
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.sql.*;
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
@ -15,49 +18,58 @@ import java.util.Comparator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.core.io.PathResource;
|
||||||
|
import org.springframework.core.io.support.EncodedResource;
|
||||||
|
import org.springframework.jdbc.datasource.init.ScriptException;
|
||||||
|
import org.springframework.jdbc.datasource.init.ScriptUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
|
import stirling.software.SPDF.config.interfaces.DatabaseInterface;
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
import stirling.software.SPDF.model.exception.BackupNotFoundException;
|
||||||
|
import stirling.software.SPDF.model.provider.UnsupportedProviderException;
|
||||||
import stirling.software.SPDF.utils.FileInfo;
|
import stirling.software.SPDF.utils.FileInfo;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
@Service
|
||||||
public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
public class DatabaseService implements DatabaseInterface {
|
||||||
|
|
||||||
@Value("${spring.datasource.url}")
|
public static final String BACKUP_PREFIX = "backup_";
|
||||||
private String url;
|
public static final String SQL_SUFFIX = ".sql";
|
||||||
|
private static final String BACKUP_DIR = "configs/db/backup/";
|
||||||
|
|
||||||
@Value("${spring.datasource.username}")
|
@Autowired private DatabaseConfig databaseConfig;
|
||||||
private String databaseUsername;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.password}")
|
|
||||||
private String databasePassword;
|
|
||||||
|
|
||||||
private Path backupPath = Paths.get("configs/db/backup/");
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there is at least one backup
|
||||||
|
*
|
||||||
|
* @return true if there are backup scripts, false if there are not
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean hasBackup() {
|
public boolean hasBackup() {
|
||||||
// Check if there is at least one backup
|
Path filePath = Paths.get(BACKUP_DIR + "*");
|
||||||
return !getBackupList().isEmpty();
|
|
||||||
|
return Files.exists(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the backup directory and filter for files with the prefix "backup_" and suffix ".sql"
|
||||||
|
*
|
||||||
|
* @return a <code>List</code> of backup files
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<FileInfo> getBackupList() {
|
public List<FileInfo> getBackupList() {
|
||||||
// Check if the backup directory exists, and create it if it does not
|
|
||||||
ensureBackupDirectoryExists();
|
|
||||||
|
|
||||||
List<FileInfo> backupFiles = new ArrayList<>();
|
List<FileInfo> backupFiles = new ArrayList<>();
|
||||||
|
Path backupPath = Paths.get(BACKUP_DIR);
|
||||||
|
|
||||||
// Read the backup directory and filter for files with the prefix "backup_" and suffix
|
|
||||||
// ".sql"
|
|
||||||
try (DirectoryStream<Path> stream =
|
try (DirectoryStream<Path> stream =
|
||||||
Files.newDirectoryStream(
|
Files.newDirectoryStream(
|
||||||
backupPath,
|
backupPath,
|
||||||
path ->
|
path ->
|
||||||
path.getFileName().toString().startsWith("backup_")
|
path.getFileName().toString().startsWith(BACKUP_PREFIX)
|
||||||
&& path.getFileName().toString().endsWith(".sql"))) {
|
&& path.getFileName().toString().endsWith(SQL_SUFFIX))) {
|
||||||
for (Path entry : stream) {
|
for (Path entry : stream) {
|
||||||
BasicFileAttributes attrs = Files.readAttributes(entry, BasicFileAttributes.class);
|
BasicFileAttributes attrs = Files.readAttributes(entry, BasicFileAttributes.class);
|
||||||
LocalDateTime modificationDate =
|
LocalDateTime modificationDate =
|
||||||
@ -78,94 +90,127 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error reading backup directory: {}", e.getMessage(), e);
|
log.error("Error reading backup directory: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return backupFiles;
|
return backupFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Imports a database backup from the specified file.
|
|
||||||
public boolean importDatabaseFromUI(String fileName) throws IOException {
|
|
||||||
return this.importDatabaseFromUI(getBackupFilePath(fileName));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Imports a database backup from the specified path.
|
|
||||||
public boolean importDatabaseFromUI(Path tempTemplatePath) throws IOException {
|
|
||||||
boolean success = executeDatabaseScript(tempTemplatePath);
|
|
||||||
if (success) {
|
|
||||||
LocalDateTime dateNow = LocalDateTime.now();
|
|
||||||
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
|
|
||||||
Path insertOutputFilePath =
|
|
||||||
this.getBackupFilePath("backup_user_" + dateNow.format(myFormatObj) + ".sql");
|
|
||||||
Files.copy(tempTemplatePath, insertOutputFilePath);
|
|
||||||
Files.deleteIfExists(tempTemplatePath);
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean importDatabase() {
|
public void importDatabase() {
|
||||||
if (!this.hasBackup()) return false;
|
if (!hasBackup()) throw new BackupNotFoundException("No backup scripts were found.");
|
||||||
|
|
||||||
List<FileInfo> backupList = this.getBackupList();
|
List<FileInfo> backupList = this.getBackupList();
|
||||||
backupList.sort(Comparator.comparing(FileInfo::getModificationDate).reversed());
|
backupList.sort(Comparator.comparing(FileInfo::getModificationDate).reversed());
|
||||||
|
|
||||||
return executeDatabaseScript(Paths.get(backupList.get(0).getFilePath()));
|
executeDatabaseScript(Paths.get(backupList.get(0).getFilePath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixMe: Needs to check the type of DB before executing script
|
/** Imports a database backup from the specified file. */
|
||||||
@Override
|
public boolean importDatabaseFromUI(String fileName) {
|
||||||
public void exportDatabase() throws IOException {
|
try {
|
||||||
// Check if the backup directory exists, and create it if it does not
|
importDatabaseFromUI(getBackupFilePath(fileName));
|
||||||
ensureBackupDirectoryExists();
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(
|
||||||
|
"Error importing database from file: {}, message: {}",
|
||||||
|
fileName,
|
||||||
|
e.getMessage(),
|
||||||
|
e.getCause());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Filter and delete old backups if there are more than 5
|
/** Imports a database backup from the specified path. */
|
||||||
|
private void importDatabaseFromUI(Path tempTemplatePath) throws IOException {
|
||||||
|
executeDatabaseScript(tempTemplatePath);
|
||||||
|
LocalDateTime dateNow = LocalDateTime.now();
|
||||||
|
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
|
||||||
|
Path insertOutputFilePath =
|
||||||
|
this.getBackupFilePath(
|
||||||
|
BACKUP_PREFIX + "user_" + dateNow.format(myFormatObj) + SQL_SUFFIX);
|
||||||
|
Files.copy(tempTemplatePath, insertOutputFilePath);
|
||||||
|
Files.deleteIfExists(tempTemplatePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Filter and delete old backups if there are more than 5 */
|
||||||
|
@Override
|
||||||
|
public void exportDatabase() throws SQLException, UnsupportedProviderException {
|
||||||
List<FileInfo> filteredBackupList =
|
List<FileInfo> filteredBackupList =
|
||||||
this.getBackupList().stream()
|
this.getBackupList().stream()
|
||||||
.filter(backup -> !backup.getFileName().startsWith("backup_user_"))
|
.filter(backup -> !backup.getFileName().startsWith(BACKUP_PREFIX + "user_"))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (filteredBackupList.size() > 5) {
|
if (filteredBackupList.size() > 5) {
|
||||||
filteredBackupList.sort(
|
deleteOldestBackup(filteredBackupList);
|
||||||
Comparator.comparing(
|
|
||||||
p -> p.getFileName().substring(7, p.getFileName().length() - 4)));
|
|
||||||
Files.deleteIfExists(Paths.get(filteredBackupList.get(0).getFilePath()));
|
|
||||||
log.info("Deleted oldest backup: {}", filteredBackupList.get(0).getFileName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDateTime dateNow = LocalDateTime.now();
|
LocalDateTime dateNow = LocalDateTime.now();
|
||||||
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
|
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
|
||||||
Path insertOutputFilePath =
|
Path insertOutputFilePath =
|
||||||
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
|
this.getBackupFilePath(BACKUP_PREFIX + dateNow.format(myFormatObj) + SQL_SUFFIX);
|
||||||
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
|
|
||||||
|
try (Connection conn = databaseConfig.connection()) {
|
||||||
|
ScriptUtils.executeSqlScript(
|
||||||
|
conn, new EncodedResource(new PathResource(insertOutputFilePath)));
|
||||||
|
|
||||||
try (Connection conn =
|
|
||||||
DriverManager.getConnection(url, databaseUsername, databasePassword);
|
|
||||||
PreparedStatement stmt = conn.prepareStatement(query)) {
|
|
||||||
stmt.setString(1, insertOutputFilePath.toString());
|
|
||||||
stmt.execute();
|
|
||||||
log.info("Database export completed: {}", insertOutputFilePath);
|
log.info("Database export completed: {}", insertOutputFilePath);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException | UnsupportedProviderException e) {
|
||||||
log.error("Error during database export: {}", e.getMessage(), e);
|
log.error("Error during database export: {}", e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
} catch (ScriptException e) {
|
||||||
|
log.error("Error during database export: File {} not found", insertOutputFilePath);
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the H2 database version.
|
private static void deleteOldestBackup(List<FileInfo> filteredBackupList) {
|
||||||
|
try {
|
||||||
|
filteredBackupList.sort(
|
||||||
|
Comparator.comparing(
|
||||||
|
p -> p.getFileName().substring(7, p.getFileName().length() - 4)));
|
||||||
|
|
||||||
|
FileInfo oldestFile = filteredBackupList.get(0);
|
||||||
|
Files.deleteIfExists(Paths.get(oldestFile.getFilePath()));
|
||||||
|
log.info("Deleted oldest backup: {}", oldestFile.getFileName());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Unable to delete oldest backup, message: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the H2 database version.
|
||||||
|
*
|
||||||
|
* @return <code>String</code> of the H2 version
|
||||||
|
*/
|
||||||
public String getH2Version() {
|
public String getH2Version() {
|
||||||
String version = "Unknown";
|
String version = "Unknown";
|
||||||
try (Connection conn =
|
|
||||||
DriverManager.getConnection(url, databaseUsername, databasePassword)) {
|
if (databaseConfig
|
||||||
try (Statement stmt = conn.createStatement();
|
.getApplicationProperties()
|
||||||
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
|
.getSystem()
|
||||||
if (rs.next()) {
|
.getDatasource()
|
||||||
version = rs.getString("version");
|
.getType()
|
||||||
log.info("H2 Database Version: {}", version);
|
.equals(ApplicationProperties.Driver.H2.name())) {
|
||||||
|
try (Connection conn = databaseConfig.connection()) {
|
||||||
|
try (Statement stmt = conn.createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
|
||||||
|
if (rs.next()) {
|
||||||
|
version = rs.getString("version");
|
||||||
|
log.info("H2 Database Version: {}", version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (SQLException | UnsupportedProviderException e) {
|
||||||
|
log.error("Error retrieving H2 version: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
|
||||||
log.error("Error retrieving H2 version: {}", e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes a backup file.
|
/**
|
||||||
|
* Deletes a backup file.
|
||||||
|
*
|
||||||
|
* @return true if successful, false if not
|
||||||
|
*/
|
||||||
public boolean deleteBackupFile(String fileName) throws IOException {
|
public boolean deleteBackupFile(String fileName) throws IOException {
|
||||||
if (!isValidFileName(fileName)) {
|
if (!isValidFileName(fileName)) {
|
||||||
log.error("Invalid file name: {}", fileName);
|
log.error("Invalid file name: {}", fileName);
|
||||||
@ -181,43 +226,37 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the Path object for a given backup file name.
|
/**
|
||||||
|
* Gets the Path for a given backup file name.
|
||||||
|
*
|
||||||
|
* @return the <code>Path</code> object for the given file name
|
||||||
|
*/
|
||||||
public Path getBackupFilePath(String fileName) {
|
public Path getBackupFilePath(String fileName) {
|
||||||
Path filePath = Paths.get(backupPath.toString(), fileName).normalize();
|
Path filePath = Paths.get(BACKUP_DIR, fileName).normalize();
|
||||||
if (!filePath.startsWith(backupPath)) {
|
if (!filePath.startsWith(BACKUP_DIR)) {
|
||||||
throw new SecurityException("Path traversal detected");
|
throw new SecurityException("Path traversal detected");
|
||||||
}
|
}
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean executeDatabaseScript(Path scriptPath) {
|
private void executeDatabaseScript(Path scriptPath) {
|
||||||
String query = "RUNSCRIPT from ?;";
|
try (Connection conn = databaseConfig.connection()) {
|
||||||
|
ScriptUtils.executeSqlScript(conn, new EncodedResource(new PathResource(scriptPath)));
|
||||||
|
|
||||||
try (Connection conn =
|
|
||||||
DriverManager.getConnection(url, databaseUsername, databasePassword);
|
|
||||||
PreparedStatement stmt = conn.prepareStatement(query)) {
|
|
||||||
stmt.setString(1, scriptPath.toString());
|
|
||||||
stmt.execute();
|
|
||||||
log.info("Database import completed: {}", scriptPath);
|
log.info("Database import completed: {}", scriptPath);
|
||||||
return true;
|
} catch (SQLException | UnsupportedProviderException e) {
|
||||||
} catch (SQLException e) {
|
|
||||||
log.error("Error during database import: {}", e.getMessage(), e);
|
log.error("Error during database import: {}", e.getMessage(), e);
|
||||||
return false;
|
} catch (ScriptException e) {
|
||||||
}
|
log.error("Error: File {} not found", scriptPath.toString(), e);
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureBackupDirectoryExists() {
|
|
||||||
if (Files.notExists(backupPath)) {
|
|
||||||
try {
|
|
||||||
Files.createDirectories(backupPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error creating directories: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for invalid characters or sequences
|
||||||
|
*
|
||||||
|
* @return true if it contains no invalid characters, false if it does
|
||||||
|
*/
|
||||||
private boolean isValidFileName(String fileName) {
|
private boolean isValidFileName(String fileName) {
|
||||||
// Check for invalid characters or sequences
|
|
||||||
return fileName != null
|
return fileName != null
|
||||||
&& !fileName.contains("..")
|
&& !fileName.contains("..")
|
||||||
&& !fileName.contains("/")
|
&& !fileName.contains("/")
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package stirling.software.SPDF.model.exception;
|
||||||
|
|
||||||
|
public class BackupNotFoundException extends RuntimeException {
|
||||||
|
public BackupNotFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package stirling.software.SPDF.config.security.database;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class DatabaseServiceTest {
|
||||||
|
|
||||||
|
private final Path BACKUP_PATH = Paths.get("configs/db/backup/*");
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DatabaseConfig databaseConfig;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DatabaseService databaseService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHasBackups() throws IOException {
|
||||||
|
Files.createDirectories(BACKUP_PATH);
|
||||||
|
|
||||||
|
assertTrue(databaseService.hasBackup());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user