refactor: remove SSH/Docker configuration options from Jitsi settings and streamline related backend queries and mutations
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,35 +7,14 @@
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
const configAtual = useQuery(api.configuracaoJitsi.obterConfigJitsi, {});
|
||||
|
||||
// Query condicional para configuração completa
|
||||
const configCompletaQuery = $derived(
|
||||
configAtual?.data?._id ? { configId: configAtual.data._id } : null
|
||||
);
|
||||
const configCompleta = useQuery(
|
||||
api.configuracaoJitsi.obterConfigJitsiCompleta,
|
||||
configCompletaQuery ? configCompletaQuery : 'skip'
|
||||
);
|
||||
|
||||
let domain = $state('');
|
||||
let appId = $state('sgse-app');
|
||||
let roomPrefix = $state('sgse');
|
||||
let useHttps = $state(false);
|
||||
let acceptSelfSignedCert = $state(false);
|
||||
|
||||
// Campos SSH/Docker
|
||||
let sshHost = $state('');
|
||||
let sshPort = $state(22);
|
||||
let sshUsername = $state('');
|
||||
let sshPassword = $state('');
|
||||
let sshKeyPath = $state('');
|
||||
let dockerComposePath = $state('');
|
||||
let jitsiConfigPath = $state('~/.jitsi-meet-cfg');
|
||||
|
||||
let mostrarConfigSSH = $state(false);
|
||||
let processando = $state(false);
|
||||
let testando = $state(false);
|
||||
let testandoSSH = $state(false);
|
||||
let aplicandoServidor = $state(false);
|
||||
let mensagem = $state<{ tipo: 'success' | 'error'; texto: string; detalhes?: string } | null>(
|
||||
null
|
||||
);
|
||||
@@ -65,19 +44,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Carregar configurações SSH/Docker
|
||||
$effect(() => {
|
||||
if (configCompleta?.data) {
|
||||
sshHost = configCompleta.data.sshHost || '';
|
||||
sshPort = configCompleta.data.sshPort || 22;
|
||||
sshUsername = configCompleta.data.sshUsername || '';
|
||||
sshPassword = ''; // Sempre limpar senha por segurança
|
||||
sshKeyPath = configCompleta.data.sshKeyPath || '';
|
||||
dockerComposePath = configCompleta.data.dockerComposePath || '';
|
||||
jitsiConfigPath = configCompleta.data.jitsiConfigPath || '~/.jitsi-meet-cfg';
|
||||
mostrarConfigSSH = !!(configCompleta.data.sshHost || configCompleta.data.sshUsername);
|
||||
}
|
||||
});
|
||||
|
||||
// Ativar HTTPS automaticamente se domínio contém porta 8443
|
||||
$effect(() => {
|
||||
@@ -117,15 +83,7 @@
|
||||
roomPrefix: roomPrefix.trim(),
|
||||
useHttps,
|
||||
acceptSelfSignedCert,
|
||||
configuradoPorId: currentUser.data._id as Id<'usuarios'>,
|
||||
// Configurações SSH/Docker (opcionais)
|
||||
sshHost: sshHost.trim() || undefined,
|
||||
sshPort: sshPort || undefined,
|
||||
sshUsername: sshUsername.trim() || undefined,
|
||||
sshPassword: sshPassword.trim() || undefined,
|
||||
sshKeyPath: sshKeyPath.trim() || undefined,
|
||||
dockerComposePath: dockerComposePath.trim() || undefined,
|
||||
jitsiConfigPath: jitsiConfigPath.trim() || undefined
|
||||
configuradoPorId: currentUser.data._id as Id<'usuarios'>
|
||||
});
|
||||
|
||||
if (resultado.sucesso) {
|
||||
@@ -173,96 +131,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function testarConexaoSSH() {
|
||||
if (!sshHost?.trim() || !sshUsername?.trim()) {
|
||||
mostrarMensagem('error', 'Preencha Host e Usuário SSH antes de testar');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sshPassword?.trim() && !sshKeyPath?.trim()) {
|
||||
mostrarMensagem('error', 'Preencha a senha SSH ou o caminho da chave antes de testar');
|
||||
return;
|
||||
}
|
||||
|
||||
testandoSSH = true;
|
||||
try {
|
||||
const resultado = await client.action(api.actions.jitsiServer.testarConexaoSSH, {
|
||||
sshHost: sshHost.trim(),
|
||||
sshPort: sshPort || 22,
|
||||
sshUsername: sshUsername.trim(),
|
||||
sshPassword: sshPassword.trim() || undefined,
|
||||
sshKeyPath: sshKeyPath.trim() || undefined
|
||||
});
|
||||
|
||||
if (resultado.sucesso) {
|
||||
mostrarMensagem('success', resultado.mensagem);
|
||||
} else {
|
||||
mostrarMensagem('error', `Erro ao testar SSH: ${resultado.erro}`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
console.error('Erro ao testar SSH:', error);
|
||||
mostrarMensagem('error', errorMessage || 'Erro ao conectar via SSH');
|
||||
} finally {
|
||||
testandoSSH = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function aplicarConfiguracaoServidor() {
|
||||
if (!configAtual?.data?._id) {
|
||||
mostrarMensagem('error', 'Salve a configuração básica antes de aplicar no servidor');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sshHost?.trim() || !sshUsername?.trim()) {
|
||||
mostrarMensagem('error', 'Configure o acesso SSH antes de aplicar no servidor');
|
||||
return;
|
||||
}
|
||||
|
||||
// Senha SSH é necessária para aplicar (pode ser a armazenada ou uma nova)
|
||||
if (!sshPassword?.trim() && !sshKeyPath?.trim() && !configCompleta?.data?.sshPasswordHash) {
|
||||
mostrarMensagem(
|
||||
'error',
|
||||
'Forneça a senha SSH ou o caminho da chave para aplicar a configuração'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!confirm(
|
||||
'Deseja aplicar essas configurações no servidor Jitsi Docker? Os containers serão reiniciados.'
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
aplicandoServidor = true;
|
||||
try {
|
||||
const resultado = await client.action(api.actions.jitsiServer.aplicarConfiguracaoServidor, {
|
||||
configId: configAtual.data._id,
|
||||
sshPassword: sshPassword.trim() || undefined
|
||||
});
|
||||
|
||||
if (resultado.sucesso) {
|
||||
mostrarMensagem('success', resultado.mensagem, resultado.detalhes);
|
||||
// Limpar senha após uso
|
||||
sshPassword = '';
|
||||
} else {
|
||||
mostrarMensagem('error', `Erro ao aplicar configuração: ${resultado.erro}`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
console.error('Erro ao aplicar configuração:', error);
|
||||
mostrarMensagem('error', errorMessage || 'Erro ao aplicar configuração no servidor');
|
||||
} finally {
|
||||
aplicandoServidor = false;
|
||||
}
|
||||
}
|
||||
|
||||
const statusConfig = $derived(configAtual?.data?.ativo ? 'Configurado' : 'Não configurado');
|
||||
|
||||
const configuradoNoServidor = $derived(configCompleta?.data?.configuradoNoServidor ?? false);
|
||||
|
||||
const isLoading = $derived(configAtual === undefined);
|
||||
const hasError = $derived(configAtual === null && !isLoading);
|
||||
</script>
|
||||
@@ -478,218 +348,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configurações SSH/Docker -->
|
||||
<div class="divider"></div>
|
||||
<div class="mb-2 flex items-center justify-between">
|
||||
<h3 class="font-bold">Configuração SSH/Docker (Opcional)</h3>
|
||||
<label class="label cursor-pointer gap-2">
|
||||
<span class="label-text text-sm">Configurar servidor via SSH</span>
|
||||
<input type="checkbox" bind:checked={mostrarConfigSSH} class="checkbox checkbox-sm" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{#if mostrarConfigSSH}
|
||||
<div class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<!-- SSH Host -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="ssh-host">
|
||||
<span class="label-text font-medium">Host SSH *</span>
|
||||
</label>
|
||||
<input
|
||||
id="ssh-host"
|
||||
type="text"
|
||||
bind:value={sshHost}
|
||||
placeholder="192.168.1.100 ou servidor.local"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">Endereço do servidor Docker</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Port -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="ssh-port">
|
||||
<span class="label-text font-medium">Porta SSH</span>
|
||||
</label>
|
||||
<input
|
||||
id="ssh-port"
|
||||
type="number"
|
||||
bind:value={sshPort}
|
||||
placeholder="22"
|
||||
min="1"
|
||||
max="65535"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- SSH Username -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="ssh-username">
|
||||
<span class="label-text font-medium">Usuário SSH *</span>
|
||||
</label>
|
||||
<input
|
||||
id="ssh-username"
|
||||
type="text"
|
||||
bind:value={sshUsername}
|
||||
placeholder="usuario"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- SSH Password ou Key Path -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="ssh-password">
|
||||
<span class="label-text font-medium">Senha SSH</span>
|
||||
</label>
|
||||
<input
|
||||
id="ssh-password"
|
||||
type="password"
|
||||
bind:value={sshPassword}
|
||||
placeholder="Deixe vazio para manter senha salva"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">Ou use caminho da chave SSH abaixo</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Key Path -->
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="ssh-key-path">
|
||||
<span class="label-text font-medium">Caminho da Chave SSH</span>
|
||||
</label>
|
||||
<input
|
||||
id="ssh-key-path"
|
||||
type="text"
|
||||
bind:value={sshKeyPath}
|
||||
placeholder="/home/usuario/.ssh/id_rsa"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">Caminho no servidor SSH para a chave privada</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Docker Compose Path -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="docker-compose-path">
|
||||
<span class="label-text font-medium">Caminho Docker Compose</span>
|
||||
</label>
|
||||
<input
|
||||
id="docker-compose-path"
|
||||
type="text"
|
||||
bind:value={dockerComposePath}
|
||||
placeholder="/home/usuario/jitsi-docker"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">Diretório com docker-compose.yml</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Jitsi Config Path -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="jitsi-config-path">
|
||||
<span class="label-text font-medium">Caminho Config Jitsi</span>
|
||||
</label>
|
||||
<input
|
||||
id="jitsi-config-path"
|
||||
type="text"
|
||||
bind:value={jitsiConfigPath}
|
||||
placeholder="~/.jitsi-meet-cfg"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">Diretório de configurações do Jitsi</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Configuração Servidor -->
|
||||
{#if configuradoNoServidor}
|
||||
<div class="alert alert-success mt-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>
|
||||
Configuração aplicada no servidor
|
||||
{#if configCompleta?.data?.configuradoNoServidorEm}
|
||||
em {new Date(configCompleta.data.configuradoNoServidorEm).toLocaleString('pt-BR')}
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Botões SSH/Docker -->
|
||||
<div class="mt-4 flex gap-3">
|
||||
<button
|
||||
class="btn btn-outline btn-info"
|
||||
onclick={testarConexaoSSH}
|
||||
disabled={testandoSSH || processando || aplicandoServidor}
|
||||
>
|
||||
{#if testandoSSH}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
Testar SSH
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-success"
|
||||
onclick={aplicarConfiguracaoServidor}
|
||||
disabled={aplicandoServidor ||
|
||||
processando ||
|
||||
testando ||
|
||||
testandoSSH ||
|
||||
!configAtual?.data?._id}
|
||||
>
|
||||
{#if aplicandoServidor}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
Aplicar no Servidor Docker
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Ações -->
|
||||
<div class="card-actions mt-6 justify-end gap-3">
|
||||
|
||||
@@ -2,7 +2,6 @@ import { v } from "convex/values";
|
||||
import { mutation, query, action, internalMutation } from "./_generated/server";
|
||||
import { registrarAtividade } from "./logsAtividades";
|
||||
import { api, internal } from "./_generated/api";
|
||||
import { encryptSMTPPassword } from "./auth/utils";
|
||||
|
||||
/**
|
||||
* Obter configuração de Jitsi ativa
|
||||
@@ -33,44 +32,6 @@ export const obterConfigJitsi = query({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Obter configuração completa de Jitsi (incluindo SSH, mas sem senha)
|
||||
*/
|
||||
export const obterConfigJitsiCompleta = query({
|
||||
args: {
|
||||
configId: v.id("configuracaoJitsi"),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const config = await ctx.db.get(args.configId);
|
||||
|
||||
if (!config) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
_id: config._id,
|
||||
domain: config.domain,
|
||||
appId: config.appId,
|
||||
roomPrefix: config.roomPrefix,
|
||||
useHttps: config.useHttps,
|
||||
acceptSelfSignedCert: config.acceptSelfSignedCert ?? false,
|
||||
ativo: config.ativo,
|
||||
testadoEm: config.testadoEm,
|
||||
atualizadoEm: config.atualizadoEm,
|
||||
configuradoEm: config.configuradoEm,
|
||||
// Configurações SSH (sem senha)
|
||||
sshHost: config.sshHost,
|
||||
sshPort: config.sshPort,
|
||||
sshUsername: config.sshUsername,
|
||||
sshPasswordHash: config.sshPasswordHash ? "********" : undefined, // Mascarar
|
||||
sshKeyPath: config.sshKeyPath,
|
||||
dockerComposePath: config.dockerComposePath,
|
||||
jitsiConfigPath: config.jitsiConfigPath,
|
||||
configuradoNoServidor: config.configuradoNoServidor ?? false,
|
||||
configuradoNoServidorEm: config.configuradoNoServidorEm,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Salvar configuração de Jitsi (apenas TI_MASTER)
|
||||
@@ -83,14 +44,6 @@ export const salvarConfigJitsi = mutation({
|
||||
useHttps: v.boolean(),
|
||||
acceptSelfSignedCert: v.boolean(),
|
||||
configuradoPorId: v.id("usuarios"),
|
||||
// Opcionais: configurações SSH/Docker
|
||||
sshHost: v.optional(v.string()),
|
||||
sshPort: v.optional(v.number()),
|
||||
sshUsername: v.optional(v.string()),
|
||||
sshPassword: v.optional(v.string()), // Senha nova (será criptografada)
|
||||
sshKeyPath: v.optional(v.string()),
|
||||
dockerComposePath: v.optional(v.string()),
|
||||
jitsiConfigPath: v.optional(v.string()),
|
||||
},
|
||||
returns: v.union(
|
||||
v.object({ sucesso: v.literal(true), configId: v.id("configuracaoJitsi") }),
|
||||
@@ -121,12 +74,6 @@ export const salvarConfigJitsi = mutation({
|
||||
};
|
||||
}
|
||||
|
||||
// Buscar config ativa anterior para manter senha SSH se não fornecida
|
||||
const configAtiva = await ctx.db
|
||||
.query("configuracaoJitsi")
|
||||
.withIndex("by_ativo", (q) => q.eq("ativo", true))
|
||||
.first();
|
||||
|
||||
// Desativar config anterior
|
||||
const configsAntigas = await ctx.db
|
||||
.query("configuracaoJitsi")
|
||||
@@ -137,16 +84,6 @@ export const salvarConfigJitsi = mutation({
|
||||
await ctx.db.patch(config._id, { ativo: false });
|
||||
}
|
||||
|
||||
// Determinar senha SSH: usar nova senha se fornecida, senão manter a atual
|
||||
let sshPasswordHash: string | undefined = undefined;
|
||||
if (args.sshPassword && args.sshPassword.trim().length > 0) {
|
||||
// Nova senha fornecida, criptografar
|
||||
sshPasswordHash = await encryptSMTPPassword(args.sshPassword);
|
||||
} else if (configAtiva && configAtiva.sshPasswordHash) {
|
||||
// Senha não fornecida, manter a atual (já criptografada)
|
||||
sshPasswordHash = configAtiva.sshPasswordHash;
|
||||
}
|
||||
|
||||
// Criar nova config
|
||||
const configId = await ctx.db.insert("configuracaoJitsi", {
|
||||
domain: args.domain.trim(),
|
||||
@@ -157,14 +94,6 @@ export const salvarConfigJitsi = mutation({
|
||||
ativo: true,
|
||||
configuradoPor: args.configuradoPorId,
|
||||
atualizadoEm: Date.now(),
|
||||
// Configurações SSH/Docker
|
||||
sshHost: args.sshHost?.trim() || undefined,
|
||||
sshPort: args.sshPort || undefined,
|
||||
sshUsername: args.sshUsername?.trim() || undefined,
|
||||
sshPasswordHash: sshPasswordHash,
|
||||
sshKeyPath: args.sshKeyPath?.trim() || undefined,
|
||||
dockerComposePath: args.dockerComposePath?.trim() || undefined,
|
||||
jitsiConfigPath: args.jitsiConfigPath?.trim() || undefined,
|
||||
});
|
||||
|
||||
// Log de atividade
|
||||
|
||||
@@ -864,14 +864,6 @@ export default defineSchema({
|
||||
roomPrefix: v.string(), // Prefixo para nomes de salas
|
||||
useHttps: v.boolean(), // Usar HTTPS
|
||||
acceptSelfSignedCert: v.optional(v.boolean()), // Aceitar certificados autoassinados (útil para desenvolvimento)
|
||||
// Configurações SSH/Docker para configuração automática do servidor
|
||||
sshHost: v.optional(v.string()), // Host SSH para acesso ao servidor Docker (ex: "192.168.1.100" ou "servidor.local")
|
||||
sshPort: v.optional(v.number()), // Porta SSH (padrão: 22)
|
||||
sshUsername: v.optional(v.string()), // Usuário SSH
|
||||
sshPasswordHash: v.optional(v.string()), // Hash da senha SSH (criptografada)
|
||||
sshKeyPath: v.optional(v.string()), // Caminho para chave SSH (alternativa à senha)
|
||||
dockerComposePath: v.optional(v.string()), // Caminho do docker-compose.yml (ex: "/home/user/jitsi-docker")
|
||||
jitsiConfigPath: v.optional(v.string()), // Caminho base das configurações Jitsi (ex: "~/.jitsi-meet-cfg")
|
||||
ativo: v.boolean(), // Configuração ativa
|
||||
testadoEm: v.optional(v.number()), // Timestamp do último teste de conexão
|
||||
configuradoEm: v.optional(v.number()), // Timestamp da última configuração do servidor Docker
|
||||
|
||||
Reference in New Issue
Block a user