diff --git a/api/wireguard_manager.py b/api/wireguard_manager.py index 0807428..524c5f8 100644 --- a/api/wireguard_manager.py +++ b/api/wireguard_manager.py @@ -294,6 +294,8 @@ class WireGuardManager(BaseServiceManager): return self.generate_config() def _write_config(self, content: str): + if content and not content.endswith('\n'): + content += '\n' with open(self._config_file(), 'w') as f: f.write(content) self._syncconf() @@ -805,12 +807,20 @@ class WireGuardManager(BaseServiceManager): """Remove the [Peer] block matching public_key from wg0.conf.""" try: content = self._read_config() - # Split on blank lines between blocks - raw_blocks = ('\n' + content).split('\n\n') + # Normalise to ensure blank-line block separators before splitting. + # Without this, a file written without trailing newline will merge + # [Interface] and the first [Peer] into one block, and the filter + # below would then delete [Interface] together with the peer. + normalised = content.replace('\n[Peer]', '\n\n[Peer]') + raw_blocks = ('\n' + normalised).split('\n\n') new_blocks = [ b for b in raw_blocks if not (f'PublicKey = {public_key}' in b and '[Peer]' in b) ] + # Never write an empty file — that would destroy the [Interface] block. + if not any('[Interface]' in b for b in new_blocks): + logger.error('remove_peer: [Interface] block would be lost — aborting write') + return False self._write_config('\n\n'.join(new_blocks).lstrip('\n')) return True except Exception as e: