Compare commits
No commits in common. "84286a69193fec91bdf5df5e5cfcd7ec4652ef66" and "0df0beea96a326041103ac9d7ea3534441438361" have entirely different histories.
84286a6919
...
0df0beea96
34
package-lock.json
generated
34
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "ifms-smart-cp",
|
||||
"version": "1.0.0",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ifms-smart-cp",
|
||||
"version": "1.0.0",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@mdi/font": "7.0.96",
|
||||
"@prisma/client": "^5.4.2",
|
||||
|
@ -18,7 +18,6 @@
|
|||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"fast-xml-parser": "^4.3.2",
|
||||
"ip": "^1.1.8",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"ldapts": "^7.0.5",
|
||||
"roboto-fontface": "*",
|
||||
|
@ -30,7 +29,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/types": "^7.21.4",
|
||||
"@types/ip": "^1.1.2",
|
||||
"@types/jsonwebtoken": "^9.0.4",
|
||||
"@types/node": "^18.15.0",
|
||||
"@types/webfontloader": "^1.6.35",
|
||||
|
@ -657,15 +655,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz",
|
||||
"integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg=="
|
||||
},
|
||||
"node_modules/@types/ip": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.2.tgz",
|
||||
"integrity": "sha512-WjV3/mz9YSlfU8E88m4ZwvRQmpTjWy4vH8K+cggBUAjmp91wvT1he132Ql8V3CsZz3SYkze3CC3AxhjaD4ZYug==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/jsonwebtoken": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.4.tgz",
|
||||
|
@ -1745,11 +1734,6 @@
|
|||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/ip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
|
@ -3357,15 +3341,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz",
|
||||
"integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg=="
|
||||
},
|
||||
"@types/ip": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.2.tgz",
|
||||
"integrity": "sha512-WjV3/mz9YSlfU8E88m4ZwvRQmpTjWy4vH8K+cggBUAjmp91wvT1he132Ql8V3CsZz3SYkze3CC3AxhjaD4ZYug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/jsonwebtoken": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.4.tgz",
|
||||
|
@ -4221,11 +4196,6 @@
|
|||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ifms-smart-cp",
|
||||
"version": "1.0.0",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"clean": "rimraf ./dist",
|
||||
"dev:web": "vite --host",
|
||||
|
@ -24,7 +24,6 @@
|
|||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"fast-xml-parser": "^4.3.2",
|
||||
"ip": "^1.1.8",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"ldapts": "^7.0.5",
|
||||
"roboto-fontface": "*",
|
||||
|
@ -36,7 +35,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/types": "^7.21.4",
|
||||
"@types/ip": "^1.1.2",
|
||||
"@types/jsonwebtoken": "^9.0.4",
|
||||
"@types/node": "^18.15.0",
|
||||
"@types/webfontloader": "^1.6.35",
|
||||
|
|
|
@ -19,8 +19,6 @@ export class LdapAuth implements Auth {
|
|||
try {
|
||||
await this.client.bind(`${this.domain}\\${username}`, password)
|
||||
|
||||
// const isAdmin = await this.isAdmin(username)
|
||||
|
||||
const search = await this.client.search(this.searchDN, {
|
||||
scope: 'sub',
|
||||
filter: `(sAMAccountName=${username})`,
|
||||
|
@ -31,8 +29,7 @@ export class LdapAuth implements Auth {
|
|||
username,
|
||||
displayName: search.searchEntries[0].displayName as string,
|
||||
domain: this.domain,
|
||||
pwdLastSet: search.searchEntries[0].pwdLastSet as string,
|
||||
isAdmin: false
|
||||
pwdLastSet: search.searchEntries[0].pwdLastSet as string
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('Error:', error)
|
||||
|
@ -42,23 +39,4 @@ export class LdapAuth implements Auth {
|
|||
await this.client.unbind()
|
||||
}
|
||||
}
|
||||
|
||||
async isAdmin(username: string): Promise<boolean> {
|
||||
const adminsGroupDN = (
|
||||
await this.client.search(this.searchDN, {
|
||||
filter: `(&(objectCategory=group)(cn=PP-PTI-Admins))`
|
||||
})
|
||||
).searchEntries[0]?.distinguishedName as string
|
||||
|
||||
const adminGroupMembers = await this.client.search(this.searchDN, {
|
||||
filter: `(memberOf:1.2.840.113556.1.4.1941:=${adminsGroupDN})`,
|
||||
attributes: ['sAMAccountName']
|
||||
})
|
||||
|
||||
const isAdmin = adminGroupMembers.searchEntries.some(
|
||||
entry => entry.sAMAccountName === username
|
||||
)
|
||||
|
||||
return isAdmin
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,6 @@ import { server } from './server'
|
|||
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
|
||||
const [major] = process.versions.node.split('.').map(Number)
|
||||
|
||||
if (major < 21) throw new Error('Node version must be >= 21.0.0')
|
||||
|
||||
export const SERVER_PORT = process.env.PORT || 8080
|
||||
|
||||
server.listen(SERVER_PORT, () => {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { PaFirewallService } from '../services/PaFirewallService'
|
||||
import { db } from '../prisma'
|
||||
import { LoginResult } from '../schemas/LoginResult'
|
||||
|
||||
export async function autoLogin({
|
||||
username,
|
||||
|
@ -10,20 +9,12 @@ export async function autoLogin({
|
|||
username: string
|
||||
domain: string
|
||||
ip: string
|
||||
}): Promise<LoginResult> {
|
||||
console.log(`AutoLogin attempt: ${domain}\\${username} from ${ip}`)
|
||||
}) {
|
||||
console.log('AutoLogin?', username, domain, ip)
|
||||
|
||||
const paHosts = await db.paHost.findMany()
|
||||
|
||||
const pa = new PaFirewallService(paHosts[0].ip, paHosts[0].key)
|
||||
|
||||
await pa.login({ username, ip, domain })
|
||||
|
||||
return {
|
||||
username,
|
||||
displayName: username,
|
||||
domain,
|
||||
pwdLastSet: '',
|
||||
isAdmin: false
|
||||
}
|
||||
return await pa.login({ username, ip, domain })
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export async function login(
|
|||
|
||||
await pa.login({ username, ip, domain: user.domain })
|
||||
|
||||
const jwt = jwtService.generateToken({
|
||||
const jwt = await jwtService.generateToken({
|
||||
displayName: user.displayName,
|
||||
username: user.username,
|
||||
domain: user.domain,
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
import { z } from 'zod'
|
||||
import ip from 'ip'
|
||||
import { db } from '../prisma'
|
||||
|
||||
type Network = {
|
||||
name: string
|
||||
shortName: string
|
||||
network: string
|
||||
}
|
||||
|
||||
const networksInfo: Array<Network> = [
|
||||
{
|
||||
name: 'Reitoria',
|
||||
shortName: 'RT',
|
||||
network: '10.0.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Aquidauana',
|
||||
shortName: 'AQ',
|
||||
network: '10.2.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Campo Grande',
|
||||
shortName: 'CG',
|
||||
network: '10.3.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Corumbá',
|
||||
shortName: 'CB',
|
||||
network: '10.4.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Coxim',
|
||||
shortName: 'CX',
|
||||
network: '10.5.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Nova Andradina',
|
||||
shortName: 'NA',
|
||||
network: '10.6.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Ponta Porã',
|
||||
shortName: 'PP',
|
||||
network: '10.7.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Três Lagoas',
|
||||
shortName: 'TL',
|
||||
network: '10.8.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Jardim',
|
||||
shortName: 'JD',
|
||||
network: '10.9.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Naviraí',
|
||||
shortName: 'NV',
|
||||
network: '10.10.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Dourados',
|
||||
shortName: 'DR',
|
||||
network: '10.11.0.0/16'
|
||||
},
|
||||
{
|
||||
name: 'Reitoria',
|
||||
shortName: 'RT',
|
||||
network: '10.1.0.0/16'
|
||||
}
|
||||
]
|
||||
|
||||
const networks = networksInfo.map(network => {
|
||||
return {
|
||||
...network,
|
||||
...ip.cidrSubnet(network.network)
|
||||
}
|
||||
})
|
||||
|
||||
export async function getNetworkForIP(ip: string) {
|
||||
z.string().ip().parse(ip)
|
||||
|
||||
const network = networks.find(network => network.contains(ip))
|
||||
|
||||
if (!network) {
|
||||
return {
|
||||
name: 'Rede desconhecida',
|
||||
shortName: '--',
|
||||
network: '?',
|
||||
isSupported: false
|
||||
}
|
||||
}
|
||||
|
||||
const paHosts = await db.paHost.findMany()
|
||||
|
||||
const paHost = paHosts.find(paHost => network?.contains(paHost.ip))
|
||||
|
||||
return {
|
||||
...network,
|
||||
isSupported: !!paHost
|
||||
}
|
||||
}
|
|
@ -2,6 +2,5 @@ export type AuthResult = {
|
|||
username: string
|
||||
displayName: string
|
||||
domain: string
|
||||
pwdLastSet?: string
|
||||
isAdmin?: boolean
|
||||
pwdLastSet: string
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ export type JwtPayload = {
|
|||
username: string
|
||||
displayName: string
|
||||
domain: string
|
||||
pwdLastSet?: string
|
||||
isAdmin?: boolean
|
||||
pwdLastSet: string
|
||||
iat?: Date // issued at
|
||||
exp?: Date // expires at
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { sign, verify } from 'jsonwebtoken'
|
||||
import { JwtPayload } from '../schemas/JwtPayload'
|
||||
import { JWT_SECRET, JWT_TTL_IN_MINUTES } from '../env'
|
||||
import { JWT_SECRET, JWT_TTL_IN_MINUTES } from '../../common/env'
|
||||
|
||||
export class JwtService {
|
||||
constructor(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { XMLParser } from 'fast-xml-parser'
|
||||
import { db } from '../prisma'
|
||||
|
||||
import { MAP_TIMEOUT_IN_MINUTES } from '../env'
|
||||
import { MAP_TIMEOUT_IN_MINUTES } from '../../common/env'
|
||||
|
||||
const xmlParser = new XMLParser({
|
||||
ignoreAttributes: false,
|
||||
|
@ -42,7 +42,7 @@ export class PaFirewallService {
|
|||
throw new Error('Failed to map user ID to IP')
|
||||
}
|
||||
|
||||
console.log(`Mapped user ${domain}\\${username} to IP ${ip}`)
|
||||
console.log(`Mapped user ${username} to IP ${ip}`)
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -8,21 +8,13 @@ import { logout } from './lib/logout'
|
|||
import { PaFirewallService } from './services/PaFirewallService'
|
||||
import { jwtService } from './lib/jwt'
|
||||
import { autoLogin } from './lib/autoLogin'
|
||||
import { JwtPayload } from './schemas/JwtPayload'
|
||||
import { getNetworkForIP } from './lib/netInfo'
|
||||
|
||||
// Created for each request
|
||||
function createContext({ req, res }: trpcExpress.CreateExpressContextOptions) {
|
||||
const ip = getIpFromRequest(req)
|
||||
const token = req.headers.authorization?.split(' ')[1]
|
||||
|
||||
let jwtPayload: JwtPayload | null = null
|
||||
|
||||
try {
|
||||
jwtPayload = token ? jwtService.verifyToken(token) : null
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
const jwtPayload = token ? jwtService.verifyToken(token) : null
|
||||
|
||||
return { ip, user: jwtPayload }
|
||||
}
|
||||
|
@ -34,16 +26,9 @@ export const t = initTRPC.context<Context>().create()
|
|||
const { query, mutation, input } = t.procedure
|
||||
|
||||
export const appRouter = t.router({
|
||||
myIp: query(async ({ ctx }) => {
|
||||
myIp: query(({ ctx }) => {
|
||||
if (!ctx.ip) throw new Error('Erro ao obter endereço IP')
|
||||
const network = await getNetworkForIP(ctx.ip)
|
||||
|
||||
return {
|
||||
name: network?.name,
|
||||
shortName: network?.shortName,
|
||||
ip: ctx.ip,
|
||||
isSupported: network?.isSupported
|
||||
}
|
||||
return ctx.ip
|
||||
}),
|
||||
|
||||
login: input(
|
||||
|
@ -64,7 +49,7 @@ export const appRouter = t.router({
|
|||
|
||||
const { username, domain } = ctx.user
|
||||
|
||||
return await autoLogin({ username, domain: domain, ip: ctx.ip })
|
||||
return await autoLogin({ username, domain: ctx.ip, ip: domain })
|
||||
}),
|
||||
|
||||
addFirewall: t.procedure
|
||||
|
|
|
@ -3,42 +3,30 @@
|
|||
<span v-if="!loadingIpAddress">
|
||||
Endereço IP deste dispositivo:
|
||||
<strong>
|
||||
<code> {{ netInfo.ip }} ({{ netInfo.name }}) </code>
|
||||
<code>
|
||||
{{ ipAddress }}
|
||||
</code>
|
||||
</strong>
|
||||
</span>
|
||||
<span v-else>
|
||||
<v-progress-circular indeterminate class="mr-2" />
|
||||
Obtendo seu endereço IP...
|
||||
</span>
|
||||
<v-alert
|
||||
type="error"
|
||||
v-if="!netInfo.isSupported && !loadingIpAddress"
|
||||
prominent
|
||||
class="mt-2"
|
||||
>
|
||||
A rede onde seu dispositivo se encontra não é suportada. Entre em contato
|
||||
com o SERTI do seu câmpus
|
||||
</v-alert>
|
||||
</v-alert>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { trpc } from '../trpc'
|
||||
|
||||
const netInfo = ref<{
|
||||
ip: string
|
||||
name?: string | undefined
|
||||
shortName?: string | undefined
|
||||
isSupported?: boolean
|
||||
}>({ ip: '', name: '', shortName: '' })
|
||||
const ipAddress = ref('')
|
||||
const loadingIpAddress = ref(false)
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
loadingIpAddress.value = true
|
||||
netInfo.value = await trpc.myIp.query()
|
||||
ipAddress.value = await trpc.myIp.query()
|
||||
} catch (error: any) {
|
||||
netInfo.value = error.message
|
||||
ipAddress.value = error.message
|
||||
} finally {
|
||||
loadingIpAddress.value = false
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import { PropType } from 'vue'
|
|||
|
||||
import { trpc } from '../trpc'
|
||||
|
||||
import { LoginResult } from '@/server/schemas/LoginResult'
|
||||
import { LoginResult } from '@/server/schemas/Auth'
|
||||
|
||||
const props = defineProps({
|
||||
loginResult: {
|
||||
|
@ -58,10 +58,10 @@ async function onLogout() {
|
|||
'Deseja realmente sair? Você será desconectado e não poderá navegar na Internet até fazer login novamente.'
|
||||
)
|
||||
) {
|
||||
const success = await trpc.logout.mutate()
|
||||
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('autoLogin')
|
||||
const success = await trpc.logout.mutate({
|
||||
username: props.loginResult.username,
|
||||
domain: props.loginResult.domain
|
||||
})
|
||||
|
||||
if (success) {
|
||||
alert('Você foi desconectado.')
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<v-switch
|
||||
v-model="autoLogin"
|
||||
color="primary"
|
||||
label="Logar automaticamente neste dispositivo?"
|
||||
label="Logar automaticamente neste dispositivo"
|
||||
hide-details
|
||||
/>
|
||||
</v-card-text>
|
||||
|
@ -61,43 +61,17 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { trpc } from '../trpc'
|
||||
import { VForm } from 'vuetify/lib/components/index.mjs'
|
||||
import LoginErrorAlert from './LoginErrorAlert.vue'
|
||||
import { useToken } from '../composables/useToken'
|
||||
|
||||
const emit = defineEmits(['login'])
|
||||
|
||||
const { token } = useToken()
|
||||
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
|
||||
const autoLogin = ref(false)
|
||||
|
||||
watch(autoLogin, value => {
|
||||
localStorage.setItem('autoLogin', value ? 'true' : 'false')
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
autoLogin.value = localStorage.getItem('autoLogin') === 'true'
|
||||
|
||||
if (autoLogin.value && token.value) {
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
const result = await trpc.autoLogin.mutate()
|
||||
|
||||
emit('login', result)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const showPassword = ref(false)
|
||||
|
||||
const loading = ref(false)
|
||||
|
@ -123,10 +97,6 @@ async function doLogin() {
|
|||
emit('login', loginResult)
|
||||
|
||||
console.log(loginResult)
|
||||
|
||||
if (loginResult.token && autoLogin.value) {
|
||||
token.value = loginResult.token
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.log(e.message)
|
||||
error.value = e.message
|
||||
|
|
|
@ -16,21 +16,6 @@ const routes = [
|
|||
import(/* webpackChunkName: "home" */ '@/views/Login.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/add-firewall',
|
||||
component: () => import('@/layouts/default/Default.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'AddFirewall',
|
||||
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "addFirewall" */ '@/views/AddFirewall.vue'
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -8,11 +8,7 @@ const SERVER_URL = import.meta.env.VITE_SERVER_URL || ''
|
|||
export const trpc = createTRPCProxyClient<AppRouter>({
|
||||
links: [
|
||||
httpBatchLink({
|
||||
url: `${SERVER_URL}/trpc`,
|
||||
headers() {
|
||||
const token = localStorage.getItem('token')
|
||||
return token ? { Authorization: token } : {}
|
||||
}
|
||||
url: `${SERVER_URL}/trpc`
|
||||
})
|
||||
]
|
||||
})
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
<template>
|
||||
<v-container class="justify-center">
|
||||
<v-row justify="center">
|
||||
<v-col xl="5" lg="6" md="7" sm="10">
|
||||
<v-alert type="info" class="mb-6">
|
||||
É necessário um usuário local com permissões de escrita na API XML
|
||||
para que o sistema possa logar os usuários. É possível usar o mesmo
|
||||
usuário usado no sistema Portal de TI.
|
||||
</v-alert>
|
||||
<v-form ref="form" @submit.prevent="submit" lazy-validation>
|
||||
<v-card title="Adicionar PA">
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
class="mb-5"
|
||||
v-model="ip"
|
||||
label="Endereço IP"
|
||||
:variant="'outlined'"
|
||||
hint="Endereço de gestão do firewall"
|
||||
prepend-inner-icon="mdi-ip"
|
||||
required
|
||||
validate-on="blur"
|
||||
:rules="[v => validIP(v) || 'Endereço IP inválido']"
|
||||
/>
|
||||
<v-text-field
|
||||
class="mb-5"
|
||||
v-model="username"
|
||||
label="Usuário local do firewall"
|
||||
:variant="'outlined'"
|
||||
hint="Usuário do firewall. Não usar usuário do Panorama"
|
||||
prepend-inner-icon="mdi-account"
|
||||
:rules="[v => !!v || 'Campo obrigatório']"
|
||||
required
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
label="Senha"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
hint="Senha do usuário local do firewall"
|
||||
:variant="'outlined'"
|
||||
autocomplete="current-password"
|
||||
prepend-inner-icon="mdi-key"
|
||||
:append-inner-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
|
||||
@click:append-inner="showPassword = !showPassword"
|
||||
:rules="[v => !!v || 'Campo obrigatório']"
|
||||
required
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
class="px-6"
|
||||
prepend-icon="mdi-plus"
|
||||
:disabled="!valid"
|
||||
size="x-large"
|
||||
color="primary"
|
||||
:variant="'flat'"
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
>
|
||||
Adicionar
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { VForm } from 'vuetify/lib/components/index.mjs'
|
||||
import { z } from 'zod'
|
||||
import { trpc } from '../trpc'
|
||||
|
||||
const form = ref<VForm>()
|
||||
|
||||
const valid = computed(() => {
|
||||
return form.value?.isValid || false
|
||||
})
|
||||
|
||||
const validIP = (v: string) => {
|
||||
return z.string().ip().safeParse(v).success
|
||||
}
|
||||
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
const ip = ref('')
|
||||
|
||||
const showPassword = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
async function submit() {
|
||||
console.log('submit')
|
||||
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
await trpc.addFirewall.mutate({
|
||||
ip: ip.value,
|
||||
username: username.value,
|
||||
password: password.value
|
||||
})
|
||||
|
||||
alert('Firewall adicionado com sucesso!')
|
||||
|
||||
router.push('/')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user