1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 07:10:09 +01:00

Backup and restore function is done

Completed with SQLDump and .conf backup
This commit is contained in:
Donald Zou 2024-10-17 00:04:26 +08:00
parent e2e821881c
commit 413377fbb9
7 changed files with 56 additions and 22 deletions

View File

@ -515,6 +515,13 @@ class WireguardConfiguration:
self.PublicKey = self.__getPublicKey() self.PublicKey = self.__getPublicKey()
self.Status = self.getStatus() self.Status = self.getStatus()
def __dropDatabase(self):
existingTables = sqlSelect(f"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '{self.Name}%'").fetchall()
for t in existingTables:
sqlUpdate(f"DROP TABLE {t['name']}")
existingTables = sqlSelect(f"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '{self.Name}%'").fetchall()
def __createDatabase(self): def __createDatabase(self):
existingTables = sqlSelect("SELECT name FROM sqlite_master WHERE type='table'").fetchall() existingTables = sqlSelect("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
@ -572,7 +579,16 @@ class WireguardConfiguration:
) )
""" % self.Name """ % self.Name
) )
def __dumpDatabase(self):
for line in sqldb.iterdump():
if (line.startswith(f"INSERT INTO \"{self.Name}\"")
or line.startswith(f'INSERT INTO "{self.Name}_restrict_access"')
or line.startswith(f'INSERT INTO "{self.Name}_transfer"')
or line.startswith(f'INSERT INTO "{self.Name}_deleted"')
):
yield line
def __getPublicKey(self) -> str: def __getPublicKey(self) -> str:
return _generatePublicKey(self.PrivateKey)[1] return _generatePublicKey(self.PrivateKey)[1]
@ -925,10 +941,14 @@ class WireguardConfiguration:
def backupConfigurationFile(self): def backupConfigurationFile(self):
if not os.path.exists(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup')): if not os.path.exists(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup')):
os.mkdir(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup')) os.mkdir(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup'))
time = datetime.now().strftime("%Y%m%d%H%M%S")
shutil.copy( shutil.copy(
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], f'{self.Name}.conf'), os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], f'{self.Name}.conf'),
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{datetime.now().strftime("%Y%m%d%H%M%S")}.conf') os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.conf')
) )
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.sql'), 'w+') as f:
for l in self.__dumpDatabase():
f.write(l + "\n")
def getBackups(self) -> list[dict[str: str, str: str, str: str]]: def getBackups(self) -> list[dict[str: str, str: str, str: str]]:
@ -959,6 +979,7 @@ class WireguardConfiguration:
if self.Status: if self.Status:
self.toggleConfiguration() self.toggleConfiguration()
target = os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', backupFileName) target = os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', backupFileName)
targetSQL = os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', backupFileName.replace(".conf", ".sql"))
if not os.path.exists(target): if not os.path.exists(target):
return False return False
targetContent = open(target, 'r').read() targetContent = open(target, 'r').read()
@ -968,6 +989,15 @@ class WireguardConfiguration:
except Exception as e: except Exception as e:
return False return False
self.__parseConfigurationFile() self.__parseConfigurationFile()
self.__dropDatabase()
self.__createDatabase()
if (os.path.exists(targetSQL)):
with open(targetSQL, 'r') as sqlFile:
for l in sqlFile.readlines():
l = l.rstrip('\n')
if len(l) > 0:
sqlUpdate(l)
self.__initPeersList() self.__initPeersList()
return True return True
@ -1518,7 +1548,7 @@ def sqlUpdate(statement: str, paramters: tuple = ()) -> sqlite3.Cursor:
cursor.execute(statement, paramters) cursor.execute(statement, paramters)
sqldb.commit() sqldb.commit()
except sqlite3.OperationalError as error: except sqlite3.OperationalError as error:
print("[WGDashboard] SQLite Error:" + str(error)) print("[WGDashboard] SQLite Error:" + str(error) + " | Statement: " + statement)
DashboardConfig = DashboardConfig() DashboardConfig = DashboardConfig()
_, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix") _, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix")

View File

@ -34,9 +34,10 @@ const restoreBackup = () => {
backupFileName: props.b.filename backupFileName: props.b.filename
}, (res) => { }, (res) => {
loading.value = false; loading.value = false;
restoreConfirmation.value = false;
if (res.status){ if (res.status){
emit("refresh") emit("refresh")
store.newMessage("Server", "Backup restored", "success") store.newMessage("Server", "Backup restored with " + props.b.filename, "success")
}else{ }else{
store.newMessage("Server", "Backup failed to restore", "danger") store.newMessage("Server", "Backup failed to restore", "danger")
} }
@ -83,7 +84,7 @@ const delaySeconds = computed(() => {
<button <button
:disabled="loading" :disabled="loading"
@click="restoreBackup()" @click="restoreBackup()"
class="btn btn-danger rounded-3"> class="btn btn-success rounded-3">
Yes Yes
</button> </button>
<button <button

View File

@ -154,7 +154,7 @@ export default {
modalOpen: false modalOpen: false
}, },
backupRestore: { backupRestore: {
modalOpen: true modalOpen: false
} }
} }
}, },

View File

@ -45,16 +45,17 @@ export default {
<LocaleText t="Configuration"></LocaleText> <LocaleText t="Configuration"></LocaleText>
</RouterLink> </RouterLink>
</div> </div>
<Transition name="fade" mode="out-in"> <TransitionGroup name="fade" tag="div" class="d-flex flex-column gap-3 mb-4">
<div v-if="this.configurationLoaded"> <p class="text-muted"
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.length === 0"> key="noConfiguration"
<LocaleText t="You don't have any WireGuard configurations yet. Please check the configuration folder or change it in Settings. By default the folder is /etc/wireguard."></LocaleText> v-if="this.configurationLoaded && this.wireguardConfigurationsStore.Configurations.length === 0">
</p> <LocaleText t="You don't have any WireGuard configurations yet. Please check the configuration folder or change it in Settings. By default the folder is /etc/wireguard."></LocaleText>
<div class="d-flex gap-3 flex-column mb-3" v-else> </p>
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard> <ConfigurationCard v-for="(c, index) in this.wireguardConfigurationsStore.Configurations"
</div> :delay="index*0.05 + 's'"
</div> v-else-if="this.configurationLoaded"
</Transition> :key="c.Name" :c="c"></ConfigurationCard>
</TransitionGroup>
</div> </div>
</div> </div>

View File

@ -12,7 +12,8 @@ export default {
Status: Boolean, Status: Boolean,
PublicKey: String, PublicKey: String,
PrivateKey: String PrivateKey: String
} },
delay: String
}, },
data(){ data(){
return{ return{
@ -105,5 +106,7 @@ export default {
</template> </template>
<style scoped> <style scoped>
.fade-enter-active{
transition-delay: v-bind(delay) !important;
}
</style> </style>

View File

@ -70,6 +70,7 @@ export const WireguardConfigurationsStore = defineStore('WireguardConfigurations
async getConfigurations(){ async getConfigurations(){
await fetchGet("/api/getWireguardConfigurations", {}, (res) => { await fetchGet("/api/getWireguardConfigurations", {}, (res) => {
if (res.status) this.Configurations = res.data if (res.status) this.Configurations = res.data
// this.Configurations = []
}); });
}, },
regexCheckIP(ip){ regexCheckIP(ip){

View File

@ -1038,14 +1038,12 @@ pre.index-alert {
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {
transition: all 0.3s ease-in-out; transition: all 0.5s cubic-bezier(0.42, 0, 0.22, 1.0);
/*position: absolute;*/
/*padding-top: 50px*/
} }
.fade-enter-from, .fade-enter-from,
.fade-leave-to { .fade-leave-to {
transform: translateY(30px); transform: translateY(40px);
opacity: 0; opacity: 0;
} }