IP Address Add
parent
6165103385
commit
277041d50d
|
|
@ -36,12 +36,15 @@ class ClientPassword(db.Model):
|
||||||
item = db.Column(db.String(255), nullable=False)
|
item = db.Column(db.String(255), nullable=False)
|
||||||
username = db.Column(db.String(255), nullable=False)
|
username = db.Column(db.String(255), nullable=False)
|
||||||
password = db.Column(db.String(255), nullable=False)
|
password = db.Column(db.String(255), nullable=False)
|
||||||
|
ip_address = db.Column(db.String(255)) # Ensure this column exists
|
||||||
client_id = db.Column(db.Integer, db.ForeignKey('client.id'), nullable=False)
|
client_id = db.Column(db.Integer, db.ForeignKey('client.id'), nullable=False)
|
||||||
category_id = db.Column(db.Integer, db.ForeignKey('password_category.id'))
|
category_id = db.Column(db.Integer, db.ForeignKey('password_category.id'))
|
||||||
category = db.relationship('PasswordCategory')
|
category = db.relationship('PasswordCategory')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<ClientPassword {self.item}>"
|
return f"<ClientPassword {self.item}>"
|
||||||
|
|
||||||
|
|
||||||
class PasswordCategory(db.Model):
|
class PasswordCategory(db.Model):
|
||||||
__tablename__ = 'password_category'
|
__tablename__ = 'password_category'
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,24 @@ def add_client_password(client_id):
|
||||||
item = request.form.get('item')
|
item = request.form.get('item')
|
||||||
username = request.form.get('username')
|
username = request.form.get('username')
|
||||||
password_text = request.form.get('password')
|
password_text = request.form.get('password')
|
||||||
|
ip_address = request.form.get('ip_address') # Capture the IP address
|
||||||
category_id = request.form.get('category_id')
|
category_id = request.form.get('category_id')
|
||||||
|
|
||||||
if item and username and password_text:
|
if item and username and password_text:
|
||||||
new_pass = ClientPassword(item=item, username=username, password=password_text, client_id=client.id)
|
new_pass = ClientPassword(
|
||||||
|
item=item,
|
||||||
|
username=username,
|
||||||
|
password=password_text,
|
||||||
|
ip_address=ip_address, # Set the IP address
|
||||||
|
client_id=client.id
|
||||||
|
)
|
||||||
if category_id:
|
if category_id:
|
||||||
new_pass.category_id = int(category_id)
|
new_pass.category_id = int(category_id)
|
||||||
db.session.add(new_pass)
|
db.session.add(new_pass)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(url_for('clients.client_detail', client_id=client.id))
|
return redirect(url_for('clients.client_detail', client_id=client.id))
|
||||||
|
|
||||||
|
|
||||||
@clients_bp.route('/clients/<int:client_id>/attach_domain', methods=['POST'])
|
@clients_bp.route('/clients/<int:client_id>/attach_domain', methods=['POST'])
|
||||||
def attach_domain(client_id):
|
def attach_domain(client_id):
|
||||||
client = Client.query.get_or_404(client_id)
|
client = Client.query.get_or_404(client_id)
|
||||||
|
|
@ -167,3 +176,32 @@ def remove_remote(client_id, remote_id):
|
||||||
db.session.delete(remote)
|
db.session.delete(remote)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(url_for('clients.client_detail', client_id=client_id))
|
return redirect(url_for('clients.client_detail', client_id=client_id))
|
||||||
|
|
||||||
|
@clients_bp.route('/clients/<int:client_id>/print', methods=['GET'])
|
||||||
|
def print_client(client_id):
|
||||||
|
client = Client.query.get_or_404(client_id)
|
||||||
|
available_domains = Domain.query.filter_by(ssl_only=False).all()
|
||||||
|
available_ssl = Domain.query.filter_by(ssl_only=True).all()
|
||||||
|
available_categories = PasswordCategory.query.all()
|
||||||
|
available_remote_categories = RemoteCategory.query.all()
|
||||||
|
# Group passwords by category.
|
||||||
|
passwords_by_category = {}
|
||||||
|
for p in client.passwords:
|
||||||
|
cat = p.category.name if p.category else "Uncategorized"
|
||||||
|
if cat not in passwords_by_category:
|
||||||
|
passwords_by_category[cat] = []
|
||||||
|
passwords_by_category[cat].append(p)
|
||||||
|
# Group remotes by category.
|
||||||
|
remotes_by_category = {}
|
||||||
|
for r in client.remotes:
|
||||||
|
cat_name = r.remote_category.name
|
||||||
|
if cat_name not in remotes_by_category:
|
||||||
|
remotes_by_category[cat_name] = []
|
||||||
|
remotes_by_category[cat_name].append(r)
|
||||||
|
return render_template('client_detail_print.html', client=client,
|
||||||
|
available_domains=available_domains,
|
||||||
|
available_ssl=available_ssl,
|
||||||
|
available_categories=available_categories,
|
||||||
|
available_remote_categories=available_remote_categories,
|
||||||
|
passwords_by_category=passwords_by_category,
|
||||||
|
remotes_by_category=remotes_by_category)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import json
|
import json
|
||||||
from flask import Blueprint, render_template, request, redirect, url_for, flash, Response
|
from flask import Blueprint, render_template, request, redirect, url_for, flash, Response
|
||||||
from app.models import Client, Domain, ClientPassword, PasswordCategory
|
from app.models import Client, Domain, ClientPassword, PasswordCategory, RemoteCategory, ClientRemote
|
||||||
from app import db
|
from app import db
|
||||||
|
|
||||||
tools_bp = Blueprint('tools', __name__)
|
tools_bp = Blueprint('tools', __name__)
|
||||||
|
|
@ -46,6 +46,7 @@ def delete_password_category(category_id):
|
||||||
flash("Category deleted and associated passwords reassigned to General.", "success")
|
flash("Category deleted and associated passwords reassigned to General.", "success")
|
||||||
return redirect(url_for('tools.password_categories'))
|
return redirect(url_for('tools.password_categories'))
|
||||||
|
|
||||||
|
|
||||||
@tools_bp.route('/tools/export_clients', methods=['GET'])
|
@tools_bp.route('/tools/export_clients', methods=['GET'])
|
||||||
def export_clients():
|
def export_clients():
|
||||||
clients = Client.query.all()
|
clients = Client.query.all()
|
||||||
|
|
@ -57,13 +58,15 @@ def export_clients():
|
||||||
'address': c.address,
|
'address': c.address,
|
||||||
'passwords': [],
|
'passwords': [],
|
||||||
'domains': [],
|
'domains': [],
|
||||||
'ssl_domains': []
|
'ssl_domains': [],
|
||||||
|
'remotes': []
|
||||||
}
|
}
|
||||||
for p in c.passwords:
|
for p in c.passwords:
|
||||||
client_dict['passwords'].append({
|
client_dict['passwords'].append({
|
||||||
'item': p.item,
|
'item': p.item,
|
||||||
'username': p.username,
|
'username': p.username,
|
||||||
'password': p.password,
|
'password': p.password,
|
||||||
|
'ip_address': p.ip_address, # Added IP address field
|
||||||
'category': p.category.name if p.category else None
|
'category': p.category.name if p.category else None
|
||||||
})
|
})
|
||||||
for d in c.domains:
|
for d in c.domains:
|
||||||
|
|
@ -80,6 +83,16 @@ def export_clients():
|
||||||
'ssl_expiration_date': d.ssl_expiration_date,
|
'ssl_expiration_date': d.ssl_expiration_date,
|
||||||
'ssl_only': d.ssl_only
|
'ssl_only': d.ssl_only
|
||||||
})
|
})
|
||||||
|
for r in c.remotes:
|
||||||
|
client_dict['remotes'].append({
|
||||||
|
'remote_category': r.remote_category.name if r.remote_category else None,
|
||||||
|
'name': r.name,
|
||||||
|
'ip_address': r.ip_address,
|
||||||
|
'port': r.port,
|
||||||
|
'psk': r.psk,
|
||||||
|
'address': r.address,
|
||||||
|
'details': r.details
|
||||||
|
})
|
||||||
data.append(client_dict)
|
data.append(client_dict)
|
||||||
json_data = json.dumps(data)
|
json_data = json.dumps(data)
|
||||||
response = Response(json_data, mimetype='application/json')
|
response = Response(json_data, mimetype='application/json')
|
||||||
|
|
@ -115,6 +128,7 @@ def import_clients():
|
||||||
item = p.get('item'),
|
item = p.get('item'),
|
||||||
username = p.get('username'),
|
username = p.get('username'),
|
||||||
password = p.get('password'),
|
password = p.get('password'),
|
||||||
|
ip_address = p.get('ip_address'), # Read the IP address from JSON
|
||||||
client_id = new_client.id,
|
client_id = new_client.id,
|
||||||
category = category
|
category = category
|
||||||
)
|
)
|
||||||
|
|
@ -149,6 +163,27 @@ def import_clients():
|
||||||
db.session.add(domain_obj)
|
db.session.add(domain_obj)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
new_client.ssl_domains.append(domain_obj)
|
new_client.ssl_domains.append(domain_obj)
|
||||||
|
# Import remote associations
|
||||||
|
for r in client_data.get('remotes', []):
|
||||||
|
remote_category_name = r.get('remote_category')
|
||||||
|
remote_category = None
|
||||||
|
if remote_category_name:
|
||||||
|
remote_category = RemoteCategory.query.filter_by(name=remote_category_name).first()
|
||||||
|
if not remote_category:
|
||||||
|
remote_category = RemoteCategory(name=remote_category_name)
|
||||||
|
db.session.add(remote_category)
|
||||||
|
db.session.flush()
|
||||||
|
new_remote = ClientRemote(
|
||||||
|
client_id = new_client.id,
|
||||||
|
remote_category = remote_category,
|
||||||
|
name = r.get('name'),
|
||||||
|
ip_address = r.get('ip_address'),
|
||||||
|
port = r.get('port'),
|
||||||
|
psk = r.get('psk'),
|
||||||
|
address = r.get('address'),
|
||||||
|
details = r.get('details')
|
||||||
|
)
|
||||||
|
db.session.add(new_remote)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Clients imported successfully", "success")
|
flash("Clients imported successfully", "success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,7 @@
|
||||||
<th>Item</th>
|
<th>Item</th>
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Password</th>
|
<th>Password</th>
|
||||||
|
<th>IP Address</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -193,6 +194,7 @@
|
||||||
<td>{{ p.item }}</td>
|
<td>{{ p.item }}</td>
|
||||||
<td>{{ p.username }}</td>
|
<td>{{ p.username }}</td>
|
||||||
<td>{{ p.password }}</td>
|
<td>{{ p.password }}</td>
|
||||||
|
<td>{{ p.ip_address }}</td>
|
||||||
<td>
|
<td>
|
||||||
<form action="{{ url_for('clients.remove_password', client_id=client.id, password_id=p.id) }}" method="post" class="d-inline">
|
<form action="{{ url_for('clients.remove_password', client_id=client.id, password_id=p.id) }}" method="post" class="d-inline">
|
||||||
<button type="submit" class="btn btn-danger btn-sm"
|
<button type="submit" class="btn btn-danger btn-sm"
|
||||||
|
|
@ -207,6 +209,8 @@
|
||||||
</table>
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<!-- Add Password Form (hidden by default) -->
|
||||||
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#passwordForm" aria-expanded="false" aria-controls="passwordForm">
|
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#passwordForm" aria-expanded="false" aria-controls="passwordForm">
|
||||||
Add Password
|
Add Password
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -226,24 +230,28 @@
|
||||||
<input type="text" class="form-control" name="password" placeholder="Password">
|
<input type="text" class="form-control" name="password" placeholder="Password">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="category">Category:</label>
|
<label for="ip_address">IP Address:</label>
|
||||||
<select name="category_id" class="form-control">
|
<input type="text" class="form-control" name="ip_address" placeholder="IP Address">
|
||||||
{% for cat in available_categories %}
|
</div>
|
||||||
{% if cat.name == "General" %}
|
<div class="form-group">
|
||||||
<option value="{{ cat.id }}" selected>{{ cat.name }}</option>
|
<label for="category">Category:</label>
|
||||||
{% else %}
|
<select name="category_id" class="form-control">
|
||||||
<option value="{{ cat.id }}">{{ cat.name }}</option>
|
{% for cat in available_categories %}
|
||||||
{% endif %}
|
{% if cat.name == "General" %}
|
||||||
{% endfor %}
|
<option value="{{ cat.id }}" selected>{{ cat.name }}</option>
|
||||||
</select>
|
{% else %}
|
||||||
</div>
|
<option value="{{ cat.id }}">{{ cat.name }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn btn-success">Add Password</button>
|
<button type="submit" class="btn btn-success">Add Password</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<!-- Section 3: Domains -->
|
<!-- Section 3: Domains -->
|
||||||
|
|
@ -345,9 +353,11 @@
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<!-- Delete Client Section -->
|
<!-- Delete Client Section -->
|
||||||
<div class="mt-4">
|
<div class="mt-4 d-flex justify-content-between">
|
||||||
<form action="{{ url_for('clients.delete_client', client_id=client.id) }}" method="post" onsubmit="return confirm('WARNING: Deleting this client will remove all associated data. Are you sure you want to proceed?');">
|
<form action="{{ url_for('clients.delete_client', client_id=client.id) }}" method="post" onsubmit="return confirm('WARNING: Deleting this client will remove all associated data. Are you sure you want to proceed?');">
|
||||||
<button type="submit" class="btn btn-danger btn-block">Delete Client</button>
|
<button type="submit" class="btn btn-danger btn-block">Delete Client</button>
|
||||||
</form>
|
</form>
|
||||||
|
<a href="{{ url_for('clients.print_client', client_id=client.id) }}" class="btn btn-secondary btn-block ml-2" target="_blank">Print</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Print - {{ client.name }}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="text-center">
|
||||||
|
<h1 class="display-4">{{ client.name }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Details Section -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h2 class="text-center">Details</h2>
|
||||||
|
<div class="text-center">
|
||||||
|
<h2>Phone: {{ client.phone or "N/A" }} | Address: {{ client.address or "N/A" }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Remote Section -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h2>Remote</h2>
|
||||||
|
{% for category, remotes in remotes_by_category.items() %}
|
||||||
|
{% if remotes|length > 0 %}
|
||||||
|
<h3 class="mt-3">{{ category }}</h3>
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead class="thead-light">
|
||||||
|
{% if category == 'RDP' %}
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>IP Address</th>
|
||||||
|
<th>Port</th>
|
||||||
|
</tr>
|
||||||
|
{% elif category == 'SSL-VPN' %}
|
||||||
|
<tr>
|
||||||
|
<th>IP Address</th>
|
||||||
|
<th>Port</th>
|
||||||
|
</tr>
|
||||||
|
{% elif category == 'VPN' %}
|
||||||
|
<tr>
|
||||||
|
<th>IP Address</th>
|
||||||
|
<th>PSK</th>
|
||||||
|
</tr>
|
||||||
|
{% elif category == 'MGMT' %}
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Address</th>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<th>Details</th>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for remote in remotes %}
|
||||||
|
<tr>
|
||||||
|
{% if category == 'RDP' %}
|
||||||
|
<td>{{ remote.name }}</td>
|
||||||
|
<td>{{ remote.ip_address }}</td>
|
||||||
|
<td>{{ remote.port }}</td>
|
||||||
|
{% elif category == 'SSL-VPN' %}
|
||||||
|
<td>{{ remote.ip_address }}</td>
|
||||||
|
<td>{{ remote.port }}</td>
|
||||||
|
{% elif category == 'VPN' %}
|
||||||
|
<td>{{ remote.ip_address }}</td>
|
||||||
|
<td>{{ remote.psk }}</td>
|
||||||
|
{% elif category == 'MGMT' %}
|
||||||
|
<td>{{ remote.name }}</td>
|
||||||
|
<td><a href="{{ remote.address }}" target="_blank">{{ remote.address }}</a></td>
|
||||||
|
{% else %}
|
||||||
|
<td>{{ remote.details }}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Passwords Section -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h2>Passwords</h2>
|
||||||
|
{% for category, passwords in passwords_by_category.items() %}
|
||||||
|
{% if passwords|length > 0 %}
|
||||||
|
<h3 class="mt-3">{{ category }}</h3>
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>Item</th>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Password</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for p in passwords %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ p.item }}</td>
|
||||||
|
<td>{{ p.username }}</td>
|
||||||
|
<td>{{ p.password }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- Domains Section -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h2>Domains</h2>
|
||||||
|
{% if client.domains|length > 0 %}
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>Domain</th>
|
||||||
|
<th>WHOIS Expiration</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for d in client.domains %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ d.domain }}</td>
|
||||||
|
<td>{{ d.expiration_date }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p>No domain associations.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- SSL Section -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<h2>SSL</h2>
|
||||||
|
{% if client.ssl_domains|length > 0 %}
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th>Domain</th>
|
||||||
|
<th>SSL Expiration</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for d in client.ssl_domains %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ d.domain }}</td>
|
||||||
|
<td>{{ d.ssl_expiration_date }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p>No SSL associations.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- You can include a print CSS or a Print button that calls window.print() if desired -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Loading…
Reference in New Issue