Added PaloAltoAddDialog

This commit is contained in:
Douglas Barone 2021-01-18 14:43:26 -04:00
parent a104e5f381
commit a7d51c8cb1
6 changed files with 373 additions and 45 deletions

BIN
web/src/assets/pa1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
web/src/assets/pa2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
web/src/assets/pa3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
web/src/assets/pa4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,15 +1,20 @@
<template> <template>
<v-container fluid> <div>
<v-toolbar flat> <v-toolbar flat>
<v-toolbar-title>Hosts cadastrados</v-toolbar-title> <v-toolbar-title>
<v-icon left>mdi-router</v-icon>
Hosts cadastrados
</v-toolbar-title>
<v-spacer /> <v-spacer />
<v-toolbar-items> <v-toolbar-items>
<v-btn text color="primary"> <palo-alto-add-dialog v-model="addDialog" />
<v-btn text color="primary" @click="addDialog = !addDialog">
<v-icon left>mdi-plus</v-icon> <v-icon left>mdi-plus</v-icon>
Adicionar Adicionar
</v-btn> </v-btn>
</v-toolbar-items> </v-toolbar-items>
</v-toolbar> </v-toolbar>
<v-container fluid>
<v-progress-circular <v-progress-circular
v-if="$apollo.queries.pAHosts.loading" v-if="$apollo.queries.pAHosts.loading"
indeterminate indeterminate
@ -25,11 +30,13 @@
md="4" md="4"
lg="3" lg="3"
> >
<v-card outlined class="rounded-xl light-shadow"> <v-card outlined class="rounded-lg light-shadow">
<v-card-title class="font-weight-light"> <v-toolbar color="secondary lighten-1" flat dark>
<v-toolbar-title>
{{ pAHost.description || pAHost.cidr.split('/')[0] }} {{ pAHost.description || pAHost.cidr.split('/')[0] }}
</v-card-title> </v-toolbar-title>
<v-card-text> </v-toolbar>
<v-list> <v-list>
<v-list-item v-for="info in infoTexts" :key="info.key"> <v-list-item v-for="info in infoTexts" :key="info.key">
<v-list-item-avatar> <v-list-item-avatar>
@ -39,20 +46,56 @@
<v-list-item-title> <v-list-item-title>
{{ pAHost[info.key] }} {{ pAHost[info.key] }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> {{ info.text }} </v-list-item-subtitle> <v-list-item-subtitle>
{{ info.text }}
</v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
</v-list> </v-list>
<v-card-text>
{{ pAHost.note || 'Sem observações' }} {{ pAHost.note || 'Sem observações' }}
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer /> <v-spacer />
<v-btn disabled icon><v-icon>mdi-pencil</v-icon></v-btn>
<v-btn icon @click="delHost(pAHost.id)"> <v-dialog max-width="600">
<template #activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on">
<v-icon>mdi-trash-can</v-icon> <v-icon>mdi-trash-can</v-icon>
</v-btn> </v-btn>
</template>
<template #default="dialog">
<v-card>
<v-toolbar flat class="display-1">
<v-toolbar-title>
<v-icon color="warning" left>mdi-alert</v-icon>
Você tem certeza?
</v-toolbar-title>
</v-toolbar>
<v-card-text class="pa-4">
O host deixará de receber o mapeamento de usuários
</v-card-text>
<v-card-actions class="justify-end">
<v-btn
text
color="error"
@click="
() => {
dialog.value = false
delHost(pAHost.id)
}
"
>
Sim, remova o host
</v-btn>
<v-btn color="success" text @click="dialog.value = false">
Cancelar
</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-col> </v-col>
@ -61,14 +104,16 @@
Nenhum host cadastrado Nenhum host cadastrado
</v-alert> </v-alert>
<v-banner icon="mdi-information" outlined rounded> <v-banner icon="mdi-information" outlined rounded>
Os hosts cadastrados serão usados para mapeamento de ID de usuários, a fim Os hosts cadastrados serão usados para mapeamento de ID de usuários, a
de evitar a necessidade da tela de autenticação do Captive Portal. fim de evitar a necessidade da tela de autenticação do Captive Portal.
</v-banner> </v-banner>
</v-container> </v-container>
</div>
</template> </template>
<script> <script>
import gql from 'graphql-tag' import gql from 'graphql-tag'
import PaloAltoAddDialog from './PaloAltoAddDialog.vue'
const PAHOSTS_QUERY = gql` const PAHOSTS_QUERY = gql`
{ {
@ -99,12 +144,16 @@ const DEL_HOST_MUTATION = gql`
export default { export default {
name: 'PaloAlto', name: 'PaloAlto',
components: {
PaloAltoAddDialog
},
data: () => ({ data: () => ({
infoTexts: [ infoTexts: [
{ key: 'cidr', text: 'IP (CIDR)', icon: 'mdi-ip' }, { key: 'cidr', text: 'IP (CIDR)', icon: 'mdi-ip' },
{ key: 'key', text: 'Chave da API', icon: 'mdi-key' }, { key: 'key', text: 'Chave da API', icon: 'mdi-key' },
{ key: 'user', text: 'Usuário da chave', icon: 'mdi-account' } { key: 'user', text: 'Usuário da chave', icon: 'mdi-account' }
] ],
addDialog: false
}), }),
apollo: { apollo: {
pAHosts: { query: PAHOSTS_QUERY, fetchPolicy: 'network-only' } pAHosts: { query: PAHOSTS_QUERY, fetchPolicy: 'network-only' }

View File

@ -0,0 +1,279 @@
<template>
<div class="text-center">
<v-dialog
v-model="dialog"
max-width="800"
:fullscreen="$vuetify.breakpoint.mdAndDown"
>
<v-stepper v-model="step">
<v-stepper-header>
<v-stepper-step :complete="step > 1" step="1">
Criar role
</v-stepper-step>
<v-stepper-step :complete="step > 2" step="2">
Criar usuário
</v-stepper-step>
<v-stepper-step :complete="step > 3" step="3">
Adicionar host
</v-stepper-step>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content step="1">
<v-card>
<v-card-title class="headline">Criar role</v-card-title>
<v-card-text>
Abra o painel de administração do firewall e navegue para
<code>Device > Admin Roles</code> e clique em <code>Add</code>.
Configure a nova <code>role</code> como nas imagens abaixo:
<v-carousel height="530">
<v-carousel-item>
<v-img src="../../assets/pa1.png" />
</v-carousel-item>
<v-carousel-item>
<v-img src="../../assets/pa2.png" />
</v-carousel-item>
<v-carousel-item>
<v-img src="../../assets/pa3.png" />
</v-carousel-item>
</v-carousel>
</v-card-text>
<v-card-actions>
<v-btn text @click="close">Cancelar</v-btn>
<v-spacer />
<v-btn depressed color="primary" @click="step = 2">
Próximo
</v-btn>
</v-card-actions>
</v-card>
</v-stepper-content>
<v-stepper-content step="2">
<v-card>
<v-card-title class="headline"> Criar usuário </v-card-title>
<v-card-text>
Crie um novo usuário utilizando a <code>Role</code> criada
anteriormente, como na imagem:
<v-img src="../../assets/pa4.png" />
</v-card-text>
<v-card-actions>
<v-btn text @click="close">Cancelar</v-btn>
<v-spacer />
<v-btn text @click="step = 1">Voltar</v-btn>
<v-btn depressed color="primary" @click="step = 3">
Próximo
</v-btn>
</v-card-actions>
</v-card>
</v-stepper-content>
<v-stepper-content step="3">
<v-card :disabled="loading" :loading="loading">
<v-card-title class="headline">
Adicionar host Palo Alto
</v-card-title>
<v-card-text>
<v-form ref="form" v-model="form" autocomplete="chrome-off">
<v-container fluid>
<v-row>
<v-col>
<v-text-field
v-model="description"
dense
outlined
label="Descrição"
hint="Ex.: PA-PP"
prepend-icon="mdi-router"
:rules="descriptionRules"
/>
</v-col>
<v-col>
<v-text-field
v-model="cidr"
dense
autocomplete="no"
outlined
label="IP (CIDR)"
prepend-icon="mdi-ip"
:rules="ipRules"
hint="O endereço IP de gestão do firewall. Ex.: 10.7.0.2/21"
validate-on-blur
/>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field
v-model="user"
autocomplete="off"
outlined
label="Usuário"
prepend-icon="mdi-account"
:rules="userRules"
hint="O usuário criado no passo anterior (ex.: pti)"
validate-on-blur
/>
</v-col>
<v-col>
<v-text-field
v-model="password"
autocomplete="new-password"
:type="showPassword ? 'text' : 'password'"
:append-icon="
showPassword ? 'mdi-eye' : 'mdi-eye-off'
"
outlined
label="Senha"
prepend-icon="mdi-key"
:rules="passwordRules"
hint="A senha usada para criar o usuário no passo anterior"
validate-on-blur
@click:append="showPassword = !showPassword"
/>
</v-col>
</v-row>
</v-container>
<v-textarea
v-model="note"
outlined
label="Anotações/observações (Opcional)"
/>
</v-form>
<v-alert outlined type="info" dismissible>
ATENÇÃO! Informar a contagem de bits da máscara de sub-rede
errada <strong>não fará o processo falhar</strong>, porém não
será possível filtrar corretamente os dispositivos que fazem
parte da mesma rede do host.
</v-alert>
</v-card-text>
<v-divider />
<v-card-actions>
<v-btn text @click="close"> Cancelar </v-btn>
<v-spacer />
<v-btn text @click="step = 2"> Voltar </v-btn>
<v-btn text color="primary" :loading="loading" @click="add">
Adicionar
</v-btn>
</v-card-actions>
</v-card>
<v-alert v-if="error" dense type="error">{{ error }}</v-alert>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</v-dialog>
</div>
</template>
<script>
import gql from 'graphql-tag'
const CIDR_RE = /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/
const ADDPAHOST_MUTATION = gql`
mutation(
$cidr: String!
$user: String!
$password: String!
$description: String!
$note: String
) {
addPAHost(
data: {
cidr: $cidr
user: $user
password: $password
description: $description
note: $note
}
) {
id
description
cidr
key
note
createdAt
updatedAt
}
}
`
export default {
name: 'PaloAltoAddDialog',
props: {
value: {
type: Boolean,
default: false
}
},
data: () => ({
loading: false,
dialog: false,
step: 3,
form: false,
showPassword: false,
description: '',
cidr: '',
user: '',
password: '',
note: '',
descriptionRules: [v => !!v || 'Digite uma descrição, por exemplo: PA-RT'],
ipRules: [
v =>
!!v ||
'Informe um endereço IP no formato CIDR, por exemplo: 10.1.0.2/21',
v => CIDR_RE.test(v) || 'Digite o IP no formato CIDR',
v => !!v.split('/')[1] || 'Digite a contagem de bits. Ex.: /21'
],
userRules: [v => !!v || 'Digite o nome de usuário.'],
passwordRules: [v => !!v || 'Digite a senha'],
error: ''
}),
watch: {
value(val) {
this.dialog = val
},
dialog(val) {
this.$emit('input', val)
}
},
methods: {
close() {
this.step = 1
this.ip = this.user = this.password = ''
this.$emit('input', false)
},
async add() {
this.$refs.form.validate()
if (this.form) {
try {
this.loading = true
this.error = ''
await this.$apollo.mutate({
mutation: ADDPAHOST_MUTATION,
variables: {
cidr: this.cidr,
user: this.user,
password: this.password,
description: this.description,
note: this.note
}
})
this.close()
} catch (e) {
this.error = e.message
} finally {
this.loading = false
}
}
}
}
}
</script>
<style></style>