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:
parent
e2e821881c
commit
413377fbb9
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -154,7 +154,7 @@ export default {
|
|||||||
modalOpen: false
|
modalOpen: false
|
||||||
},
|
},
|
||||||
backupRestore: {
|
backupRestore: {
|
||||||
modalOpen: true
|
modalOpen: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
@ -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){
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user