Akoda35 commited on
Commit
b4b2b21
·
verified ·
1 Parent(s): 7ef360a

Upload 3 files

Browse files
templates/cpanel/secrets/create.html ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Add Secret - PyRunner{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="flex">
7
+ {% include "cpanel/_sidebar.html" %}
8
+
9
+ <div class="flex-1 p-8">
10
+ <!-- Header -->
11
+ <div class="mb-8">
12
+ <nav class="flex items-center space-x-2 text-sm text-code-muted mb-4">
13
+ <a href="{% url 'cpanel:secret_list' %}" class="hover:text-code-accent">Secrets</a>
14
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
15
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
16
+ </svg>
17
+ <span class="text-code-text">Add Secret</span>
18
+ </nav>
19
+ <h1 class="text-2xl font-bold text-code-text">Add New Secret</h1>
20
+ <p class="text-code-muted">Store an encrypted credential for use in scripts</p>
21
+ </div>
22
+
23
+ <!-- Form -->
24
+ <div class="bg-code-surface border border-code-border rounded-xl p-6 max-w-2xl">
25
+ <form method="post" autocomplete="off">
26
+ {% csrf_token %}
27
+
28
+ <!-- Key Name -->
29
+ <div class="mb-6">
30
+ <label for="id_key" class="block text-sm font-medium text-code-text mb-2">
31
+ {{ form.key.label }}
32
+ </label>
33
+ {{ form.key }}
34
+ {% if form.key.help_text %}
35
+ <p class="mt-1 text-sm text-code-muted">{{ form.key.help_text }}</p>
36
+ {% endif %}
37
+ {% if form.key.errors %}
38
+ <p class="mt-1 text-sm text-code-red">{{ form.key.errors.0 }}</p>
39
+ {% endif %}
40
+ </div>
41
+
42
+ <!-- Secret Value -->
43
+ <div class="mb-6">
44
+ <label for="id_value" class="block text-sm font-medium text-code-text mb-2">
45
+ {{ form.value.label }}
46
+ </label>
47
+ {{ form.value }}
48
+ {% if form.value.help_text %}
49
+ <p class="mt-1 text-sm text-code-muted">{{ form.value.help_text }}</p>
50
+ {% endif %}
51
+ {% if form.value.errors %}
52
+ <p class="mt-1 text-sm text-code-red">{{ form.value.errors.0 }}</p>
53
+ {% endif %}
54
+ </div>
55
+
56
+ <!-- Description -->
57
+ <div class="mb-6">
58
+ <label for="id_description" class="block text-sm font-medium text-code-text mb-2">
59
+ {{ form.description.label }}
60
+ </label>
61
+ {{ form.description }}
62
+ {% if form.description.help_text %}
63
+ <p class="mt-1 text-sm text-code-muted">{{ form.description.help_text }}</p>
64
+ {% endif %}
65
+ {% if form.description.errors %}
66
+ <p class="mt-1 text-sm text-code-red">{{ form.description.errors.0 }}</p>
67
+ {% endif %}
68
+ </div>
69
+
70
+ <!-- Security Notice -->
71
+ <div class="mb-6 p-4 bg-code-bg border border-code-border rounded-lg">
72
+ <div class="flex items-start space-x-3">
73
+ <svg class="w-5 h-5 text-code-accent mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
74
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
75
+ </svg>
76
+ <div class="text-sm text-code-muted">
77
+ <p class="font-medium text-code-text">Security</p>
78
+ <ul class="mt-1 space-y-1 list-disc list-inside">
79
+ <li>Secret values are encrypted at rest using Fernet</li>
80
+ <li>Full values are never displayed after creation</li>
81
+ <li>Secrets are injected as environment variables at runtime</li>
82
+ </ul>
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ <!-- Actions -->
88
+ <div class="flex items-center justify-end space-x-4 pt-6 border-t border-code-border">
89
+ <a href="{% url 'cpanel:secret_list' %}"
90
+ class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded-lg transition-colors">
91
+ Cancel
92
+ </a>
93
+ <button type="submit"
94
+ class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors">
95
+ Add Secret
96
+ </button>
97
+ </div>
98
+ </form>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ {% endblock %}
templates/cpanel/secrets/edit.html ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Edit {{ secret.key }} - PyRunner{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="flex">
7
+ {% include "cpanel/_sidebar.html" %}
8
+
9
+ <div class="flex-1 p-8">
10
+ <!-- Header -->
11
+ <div class="mb-8">
12
+ <nav class="flex items-center space-x-2 text-sm text-code-muted mb-4">
13
+ <a href="{% url 'cpanel:secret_list' %}" class="hover:text-code-accent">Secrets</a>
14
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
15
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
16
+ </svg>
17
+ <span class="text-code-text">Edit {{ secret.key }}</span>
18
+ </nav>
19
+ <h1 class="text-2xl font-bold text-code-text">Edit Secret</h1>
20
+ <p class="text-code-muted">Update the value or description (key cannot be changed)</p>
21
+ </div>
22
+
23
+ <!-- Form -->
24
+ <div class="bg-code-surface border border-code-border rounded-xl p-6 max-w-2xl">
25
+ <form method="post" autocomplete="off">
26
+ {% csrf_token %}
27
+
28
+ <!-- Key Name (Read-only) -->
29
+ <div class="mb-6">
30
+ <label class="block text-sm font-medium text-code-text mb-2">Key Name</label>
31
+ <div class="px-4 py-3 bg-code-bg border border-code-border rounded-lg font-mono text-code-accent">
32
+ {{ secret.key }}
33
+ </div>
34
+ <p class="mt-1 text-sm text-code-muted">Key cannot be changed after creation</p>
35
+ </div>
36
+
37
+ <!-- Current Value Preview -->
38
+ <div class="mb-6">
39
+ <label class="block text-sm font-medium text-code-text mb-2">Current Value</label>
40
+ <div class="px-4 py-3 bg-code-bg border border-code-border rounded-lg font-mono text-code-muted">
41
+ {{ secret.get_masked_value }}
42
+ </div>
43
+ </div>
44
+
45
+ <!-- New Secret Value -->
46
+ <div class="mb-6">
47
+ <label for="id_value" class="block text-sm font-medium text-code-text mb-2">
48
+ {{ form.value.label }}
49
+ </label>
50
+ {{ form.value }}
51
+ {% if form.value.help_text %}
52
+ <p class="mt-1 text-sm text-code-muted">{{ form.value.help_text }}</p>
53
+ {% endif %}
54
+ {% if form.value.errors %}
55
+ <p class="mt-1 text-sm text-code-red">{{ form.value.errors.0 }}</p>
56
+ {% endif %}
57
+ </div>
58
+
59
+ <!-- Description -->
60
+ <div class="mb-6">
61
+ <label for="id_description" class="block text-sm font-medium text-code-text mb-2">
62
+ {{ form.description.label }}
63
+ </label>
64
+ {{ form.description }}
65
+ {% if form.description.errors %}
66
+ <p class="mt-1 text-sm text-code-red">{{ form.description.errors.0 }}</p>
67
+ {% endif %}
68
+ </div>
69
+
70
+ <!-- Actions -->
71
+ <div class="flex items-center justify-end space-x-4 pt-6 border-t border-code-border">
72
+ <a href="{% url 'cpanel:secret_list' %}"
73
+ class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded-lg transition-colors">
74
+ Cancel
75
+ </a>
76
+ <button type="submit"
77
+ class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors">
78
+ Save Changes
79
+ </button>
80
+ </div>
81
+ </form>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ {% endblock %}
templates/cpanel/secrets/list.html ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Secrets - PyRunner{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="flex">
7
+ {% include "cpanel/_sidebar.html" %}
8
+
9
+ <div class="flex-1 p-8">
10
+ <!-- Header -->
11
+ <div class="flex items-start justify-between mb-8">
12
+ <div>
13
+ <h1 class="text-2xl font-bold text-code-text">Secrets</h1>
14
+ <p class="text-code-muted">Encrypted credentials injected into scripts as environment variables</p>
15
+ </div>
16
+ {% if encryption_configured %}
17
+ <a href="{% url 'cpanel:secret_create' %}"
18
+ class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors inline-flex items-center">
19
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
21
+ </svg>
22
+ Add Secret
23
+ </a>
24
+ {% endif %}
25
+ </div>
26
+
27
+ <!-- Messages -->
28
+ {% if messages %}
29
+ <div class="mb-6 space-y-2">
30
+ {% for message in messages %}
31
+ <div class="p-4 rounded-lg {% if message.tags == 'error' %}bg-code-red/10 border border-code-red/30 text-code-red{% elif message.tags == 'success' %}bg-code-green/10 border border-code-green/30 text-code-green{% else %}bg-code-accent/10 border border-code-accent/30 text-code-accent{% endif %}">
32
+ {{ message }}
33
+ </div>
34
+ {% endfor %}
35
+ </div>
36
+ {% endif %}
37
+
38
+ <!-- Encryption Warning -->
39
+ {% if not encryption_configured %}
40
+ <div class="mb-6 p-4 bg-code-red/10 border border-code-red/30 rounded-lg">
41
+ <div class="flex items-start space-x-3">
42
+ <svg class="w-5 h-5 text-code-red mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
43
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
44
+ </svg>
45
+ <div>
46
+ <h3 class="font-medium text-code-red">Encryption Not Configured</h3>
47
+ <p class="text-sm text-code-red/80 mt-1">
48
+ Set the ENCRYPTION_KEY environment variable to enable secrets management.
49
+ Generate a key with:
50
+ </p>
51
+ <code class="block mt-2 p-2 bg-code-bg rounded text-xs font-mono text-code-text">
52
+ python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
53
+ </code>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ {% endif %}
58
+
59
+ <!-- Secrets Table -->
60
+ {% if secrets %}
61
+ <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden">
62
+ <table class="w-full">
63
+ <thead class="bg-code-bg border-b border-code-border">
64
+ <tr>
65
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Key</th>
66
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Value</th>
67
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Description</th>
68
+ <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Updated</th>
69
+ <th class="px-6 py-3 text-right text-xs font-semibold text-code-muted uppercase tracking-wider">Actions</th>
70
+ </tr>
71
+ </thead>
72
+ <tbody class="divide-y divide-code-border">
73
+ {% for secret in secrets %}
74
+ <tr class="hover:bg-code-bg/50 transition-colors">
75
+ <td class="px-6 py-4">
76
+ <span class="font-mono text-code-accent">{{ secret.key }}</span>
77
+ </td>
78
+ <td class="px-6 py-4">
79
+ <span class="font-mono text-code-muted text-sm">{{ secret.get_masked_value }}</span>
80
+ </td>
81
+ <td class="px-6 py-4 text-code-text text-sm max-w-xs truncate">
82
+ {{ secret.description|default:"-" }}
83
+ </td>
84
+ <td class="px-6 py-4 text-code-muted text-sm">
85
+ {{ secret.updated_at|timesince }} ago
86
+ </td>
87
+ <td class="px-6 py-4 text-right">
88
+ <div class="flex items-center justify-end space-x-2">
89
+ <a href="{% url 'cpanel:secret_edit' pk=secret.pk %}"
90
+ class="px-3 py-1.5 text-sm bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded transition-colors">
91
+ Edit
92
+ </a>
93
+ <form method="post" action="{% url 'cpanel:secret_delete' pk=secret.pk %}"
94
+ onsubmit="return confirm('Are you sure you want to delete the secret {{ secret.key }}? Scripts using this secret will fail.');"
95
+ class="inline">
96
+ {% csrf_token %}
97
+ <button type="submit"
98
+ class="px-3 py-1.5 text-sm bg-code-red/10 border border-code-red/30 hover:bg-code-red/20 text-code-red rounded transition-colors">
99
+ Delete
100
+ </button>
101
+ </form>
102
+ </div>
103
+ </td>
104
+ </tr>
105
+ {% endfor %}
106
+ </tbody>
107
+ </table>
108
+ </div>
109
+
110
+ <!-- Usage Info -->
111
+ <div class="mt-6 p-4 bg-code-bg border border-code-border rounded-lg">
112
+ <h3 class="text-sm font-medium text-code-text mb-2">Using Secrets in Scripts</h3>
113
+ <p class="text-sm text-code-muted mb-2">
114
+ All secrets are automatically injected as environment variables when your scripts run.
115
+ </p>
116
+ <code class="block p-3 bg-code-surface rounded text-sm font-mono text-code-text">
117
+ import os<br>
118
+ api_key = os.environ['YOUR_SECRET_KEY']
119
+ </code>
120
+ </div>
121
+ {% else %}
122
+ <div class="bg-code-surface border border-code-border rounded-xl p-12 text-center">
123
+ <div class="w-16 h-16 bg-code-accent/20 rounded-full flex items-center justify-center mx-auto mb-4">
124
+ <svg class="w-8 h-8 text-code-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">
125
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/>
126
+ </svg>
127
+ </div>
128
+ <h3 class="text-lg font-semibold text-code-text mb-2">No secrets yet</h3>
129
+ <p class="text-code-muted mb-6">Add your first secret to store API keys and credentials securely.</p>
130
+ {% if encryption_configured %}
131
+ <a href="{% url 'cpanel:secret_create' %}"
132
+ class="px-6 py-2 bg-code-accent hover:bg-code-accent/90 text-white font-semibold rounded-lg transition-colors inline-flex items-center">
133
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
134
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
135
+ </svg>
136
+ Add Secret
137
+ </a>
138
+ {% endif %}
139
+ </div>
140
+ {% endif %}
141
+ </div>
142
+ </div>
143
+ {% endblock %}