mailcatcher-ng 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,236 @@
1
+ <!DOCTYPE html>
2
+ <html class="mailcatcher">
3
+ <head>
4
+ <title>Server Information - MailCatcher</title>
5
+ <base href="<%= settings.prefix.chomp("/") %>/">
6
+ <link href="favicon.ico" rel="icon">
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
16
+ background: #f5f5f5;
17
+ color: #1a1a1a;
18
+ min-height: 100vh;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: 20px;
23
+ }
24
+
25
+ .container {
26
+ background: white;
27
+ border-radius: 8px;
28
+ padding: 40px;
29
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
30
+ max-width: 700px;
31
+ width: 100%;
32
+ }
33
+
34
+ h1 {
35
+ font-size: 24px;
36
+ font-weight: 700;
37
+ margin: 0 0 10px 0;
38
+ color: #1a1a1a;
39
+ }
40
+
41
+ .page-subtitle {
42
+ font-size: 13px;
43
+ color: #666;
44
+ margin-bottom: 32px;
45
+ margin-top: 4px;
46
+ }
47
+
48
+ .info-section {
49
+ margin-bottom: 32px;
50
+ }
51
+
52
+ .section-title {
53
+ font-size: 12px;
54
+ font-weight: 600;
55
+ color: #5f5f5f;
56
+ text-transform: uppercase;
57
+ letter-spacing: 0.5px;
58
+ margin-bottom: 16px;
59
+ padding-bottom: 8px;
60
+ border-bottom: 1px solid #e8eaed;
61
+ }
62
+
63
+ .info-grid {
64
+ display: grid;
65
+ grid-template-columns: 1fr 1fr;
66
+ gap: 16px;
67
+ margin-bottom: 16px;
68
+ }
69
+
70
+ .info-item {
71
+ padding: 12px 14px;
72
+ background: #f9f9f9;
73
+ border-left: 3px solid #2196F3;
74
+ border-radius: 4px;
75
+ }
76
+
77
+ .info-item.full {
78
+ grid-column: 1 / -1;
79
+ }
80
+
81
+ .info-label {
82
+ font-size: 11px;
83
+ font-weight: 600;
84
+ color: #666;
85
+ text-transform: uppercase;
86
+ letter-spacing: 0.5px;
87
+ display: block;
88
+ margin-bottom: 6px;
89
+ }
90
+
91
+ .info-value {
92
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Courier New', monospace;
93
+ font-size: 14px;
94
+ color: #1a1a1a;
95
+ word-break: break-all;
96
+ }
97
+
98
+ .button-group {
99
+ display: flex;
100
+ gap: 12px;
101
+ margin-top: 32px;
102
+ flex-wrap: wrap;
103
+ }
104
+
105
+ .btn {
106
+ padding: 10px 16px;
107
+ border: none;
108
+ border-radius: 6px;
109
+ font-size: 13px;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ transition: all 0.2s;
113
+ display: inline-flex;
114
+ align-items: center;
115
+ gap: 6px;
116
+ text-decoration: none;
117
+ }
118
+
119
+ .btn-primary {
120
+ background: #2196F3;
121
+ color: #ffffff;
122
+ }
123
+
124
+ .btn-primary:hover {
125
+ background: #1976D2;
126
+ box-shadow: 0 2px 8px rgba(33, 150, 243, 0.2);
127
+ }
128
+
129
+ .btn-secondary {
130
+ background: #f0f0f0;
131
+ color: #1a1a1a;
132
+ border: 1px solid #e0e0e0;
133
+ }
134
+
135
+ .btn-secondary:hover {
136
+ background: #e8e8e8;
137
+ border-color: #d0d0d0;
138
+ }
139
+
140
+ .btn:active {
141
+ transform: scale(0.98);
142
+ }
143
+
144
+ .btn svg {
145
+ width: 16px;
146
+ height: 16px;
147
+ }
148
+
149
+ .version-info {
150
+ font-size: 12px;
151
+ color: #999;
152
+ margin-top: 24px;
153
+ padding-top: 16px;
154
+ border-top: 1px solid #e8eaed;
155
+ text-align: center;
156
+ }
157
+ </style>
158
+ </head>
159
+ <body>
160
+ <div class="container">
161
+ <h1>Server Information</h1>
162
+ <div class="page-subtitle">Configuration and connection details</div>
163
+
164
+ <div class="info-section">
165
+ <div class="section-title">Network Configuration</div>
166
+
167
+ <div class="info-item full">
168
+ <span class="info-label">Hostname</span>
169
+ <div class="info-value"><%= @hostname %></div>
170
+ </div>
171
+
172
+ <div class="info-item full">
173
+ <span class="info-label">FQDN (Fully Qualified Domain Name)</span>
174
+ <div class="info-value"><%= @fqdn %></div>
175
+ </div>
176
+ </div>
177
+
178
+ <div class="info-section">
179
+ <div class="section-title">SMTP Server</div>
180
+
181
+ <div class="info-item">
182
+ <span class="info-label">IP Address</span>
183
+ <div class="info-value"><%= @smtp_ip %></div>
184
+ </div>
185
+
186
+ <div class="info-item">
187
+ <span class="info-label">Port</span>
188
+ <div class="info-value"><%= @smtp_port %></div>
189
+ </div>
190
+ </div>
191
+
192
+ <div class="info-section">
193
+ <div class="section-title">HTTP Server</div>
194
+
195
+ <div class="info-item">
196
+ <span class="info-label">IP Address</span>
197
+ <div class="info-value"><%= @http_ip %></div>
198
+ </div>
199
+
200
+ <div class="info-item">
201
+ <span class="info-label">Port</span>
202
+ <div class="info-value"><%= @http_port %></div>
203
+ </div>
204
+
205
+ <div class="info-item full">
206
+ <span class="info-label">Base Path</span>
207
+ <div class="info-value"><%= @http_path %></div>
208
+ </div>
209
+ </div>
210
+
211
+ <div class="button-group">
212
+ <a href="<%= settings.prefix.chomp("/") %>/" class="btn btn-primary">
213
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
214
+ <line x1="19" y1="12" x2="5" y2="12"></line>
215
+ <polyline points="12 19 5 12 12 5"></polyline>
216
+ </svg>
217
+ Back to Inbox
218
+ </a>
219
+ <a href="<%= File.join(settings.prefix.chomp("/"), "websocket-test") %>" class="btn btn-secondary">
220
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
221
+ <circle cx="12" cy="12" r="1"></circle>
222
+ <path d="M12 1v6m0 6v4"></path>
223
+ <path d="M4.22 4.22l4.24 4.24m5.08 5.08l4.24 4.24"></path>
224
+ <path d="M1 12h6m6 0h4"></path>
225
+ <path d="M4.22 19.78l4.24-4.24m5.08-5.08l4.24-4.24"></path>
226
+ </svg>
227
+ Diagnostics
228
+ </a>
229
+ </div>
230
+
231
+ <div class="version-info">
232
+ MailCatcher v<%= @version %>
233
+ </div>
234
+ </div>
235
+ </body>
236
+ </html>
@@ -0,0 +1,263 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>MailCatcher WebSocket Test</title>
5
+ <style>
6
+ body {
7
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
8
+ max-width: 800px;
9
+ margin: 40px auto;
10
+ padding: 20px;
11
+ background: #f5f5f5;
12
+ }
13
+ .container {
14
+ background: white;
15
+ border-radius: 8px;
16
+ padding: 30px;
17
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
18
+ }
19
+ h1 {
20
+ color: #333;
21
+ margin-top: 0;
22
+ }
23
+ .status {
24
+ display: flex;
25
+ align-items: center;
26
+ margin: 20px 0;
27
+ padding: 12px 16px;
28
+ background: #f0f0f0;
29
+ border-radius: 4px;
30
+ font-weight: 500;
31
+ }
32
+ .status-indicator {
33
+ display: inline-block;
34
+ width: 12px;
35
+ height: 12px;
36
+ border-radius: 50%;
37
+ margin-right: 12px;
38
+ }
39
+ .status-indicator.connected {
40
+ background: #4CAF50;
41
+ }
42
+ .status-indicator.disconnected {
43
+ background: #f44336;
44
+ }
45
+ .status-indicator.connecting {
46
+ background: #ff9800;
47
+ animation: pulse 1s infinite;
48
+ }
49
+ @keyframes pulse {
50
+ 0%, 100% { opacity: 1; }
51
+ 50% { opacity: 0.5; }
52
+ }
53
+ .buttons {
54
+ display: flex;
55
+ gap: 12px;
56
+ margin: 20px 0;
57
+ }
58
+ button {
59
+ padding: 10px 20px;
60
+ background: #2196F3;
61
+ color: white;
62
+ border: none;
63
+ border-radius: 4px;
64
+ cursor: pointer;
65
+ font-size: 14px;
66
+ font-weight: 500;
67
+ }
68
+ button:hover {
69
+ background: #1976D2;
70
+ }
71
+ button:active {
72
+ transform: scale(0.98);
73
+ }
74
+ .log {
75
+ background: #f9f9f9;
76
+ border: 1px solid #ddd;
77
+ border-radius: 4px;
78
+ padding: 15px;
79
+ max-height: 400px;
80
+ overflow-y: auto;
81
+ font-family: 'Monaco', 'Courier New', monospace;
82
+ font-size: 12px;
83
+ line-height: 1.6;
84
+ margin-top: 20px;
85
+ }
86
+ .log-entry {
87
+ margin: 8px 0;
88
+ display: flex;
89
+ gap: 12px;
90
+ }
91
+ .log-time {
92
+ color: #999;
93
+ min-width: 90px;
94
+ flex-shrink: 0;
95
+ }
96
+ .log-message {
97
+ flex: 1;
98
+ color: #333;
99
+ }
100
+ .log-message.info { color: #2196F3; }
101
+ .log-message.success { color: #4CAF50; }
102
+ .log-message.error { color: #f44336; }
103
+ .info-grid {
104
+ display: grid;
105
+ grid-template-columns: 1fr 1fr;
106
+ gap: 12px;
107
+ margin-top: 20px;
108
+ }
109
+ .info-item {
110
+ padding: 12px;
111
+ background: #f9f9f9;
112
+ border-left: 3px solid #2196F3;
113
+ border-radius: 2px;
114
+ }
115
+ .info-item label {
116
+ font-weight: 600;
117
+ color: #666;
118
+ display: block;
119
+ margin-bottom: 4px;
120
+ }
121
+ .info-item value {
122
+ font-family: monospace;
123
+ color: #333;
124
+ display: block;
125
+ }
126
+ </style>
127
+ </head>
128
+ <body>
129
+ <div class="container">
130
+ <h1>MailCatcher WebSocket Test</h1>
131
+
132
+ <div class="status">
133
+ <div class="status-indicator disconnected" id="statusIndicator"></div>
134
+ <span id="statusText">Status: Disconnected</span>
135
+ </div>
136
+
137
+ <div class="info-grid">
138
+ <div class="info-item">
139
+ <label>WebSocket URL:</label>
140
+ <value id="wsUrl"></value>
141
+ </div>
142
+ <div class="info-item">
143
+ <label>Ready State:</label>
144
+ <value id="readyState">Not initialized</value>
145
+ </div>
146
+ </div>
147
+
148
+ <div class="buttons">
149
+ <button onclick="testWebSocket()">Test WebSocket Connection</button>
150
+ <button onclick="clearLog()">Clear Log</button>
151
+ </div>
152
+
153
+ <div class="log" id="log"></div>
154
+ </div>
155
+
156
+ <script>
157
+ let ws = null;
158
+
159
+ function getWebSocketURL() {
160
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
161
+ const host = window.location.host;
162
+ const basePath = '<%= settings.prefix.chomp("/") %>';
163
+ return `${protocol}//${host}${basePath}/messages`;
164
+ }
165
+
166
+ function updateStatus(connected, message) {
167
+ const indicator = document.getElementById('statusIndicator');
168
+ const statusText = document.getElementById('statusText');
169
+
170
+ indicator.className = 'status-indicator';
171
+ if (connected === true) {
172
+ indicator.classList.add('connected');
173
+ statusText.textContent = `Status: ✓ Connected`;
174
+ } else if (connected === false) {
175
+ indicator.classList.add('disconnected');
176
+ statusText.textContent = `Status: ✗ ${message || 'Disconnected'}`;
177
+ } else {
178
+ indicator.classList.add('connecting');
179
+ statusText.textContent = `Status: ⟳ Connecting...`;
180
+ }
181
+ }
182
+
183
+ function updateReadyState() {
184
+ const readyStateDiv = document.getElementById('readyState');
185
+ if (ws) {
186
+ const states = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
187
+ readyStateDiv.textContent = `${ws.readyState} (${states[ws.readyState]})`;
188
+ }
189
+ }
190
+
191
+ function addLog(message, type = 'info') {
192
+ const logDiv = document.getElementById('log');
193
+ const entry = document.createElement('div');
194
+ entry.className = 'log-entry';
195
+
196
+ const time = new Date();
197
+ const timeStr = time.toLocaleTimeString();
198
+
199
+ const timeEl = document.createElement('div');
200
+ timeEl.className = 'log-time';
201
+ timeEl.textContent = `[${timeStr}]`;
202
+
203
+ const msgEl = document.createElement('div');
204
+ msgEl.className = `log-message ${type}`;
205
+ msgEl.textContent = message;
206
+
207
+ entry.appendChild(timeEl);
208
+ entry.appendChild(msgEl);
209
+ logDiv.appendChild(entry);
210
+ logDiv.scrollTop = logDiv.scrollHeight;
211
+ }
212
+
213
+ function clearLog() {
214
+ document.getElementById('log').innerHTML = '';
215
+ }
216
+
217
+ function testWebSocket() {
218
+ addLog('Attempting to connect to WebSocket...', 'info');
219
+
220
+ const wsUrl = getWebSocketURL();
221
+ document.getElementById('wsUrl').textContent = wsUrl;
222
+
223
+ updateStatus(null);
224
+
225
+ try {
226
+ ws = new WebSocket(wsUrl);
227
+
228
+ ws.onopen = function() {
229
+ addLog('✓ WebSocket connection established!', 'success');
230
+ updateStatus(true);
231
+ updateReadyState();
232
+ };
233
+
234
+ ws.onmessage = function(event) {
235
+ addLog(`Received: ${event.data.substring(0, 100)}${event.data.length > 100 ? '...' : ''}`, 'info');
236
+ };
237
+
238
+ ws.onerror = function(error) {
239
+ addLog(`✗ WebSocket error: ${error}`, 'error');
240
+ updateStatus(false, 'Error');
241
+ updateReadyState();
242
+ };
243
+
244
+ ws.onclose = function(event) {
245
+ addLog(`✗ WebSocket closed: Code ${event.code}, Reason: ${event.reason || 'No reason'}`, 'error');
246
+ updateStatus(false, `Closed (Code: ${event.code})`);
247
+ updateReadyState();
248
+ ws = null;
249
+ };
250
+ } catch (e) {
251
+ addLog(`✗ Exception: ${e.message}`, 'error');
252
+ updateStatus(false, 'Exception');
253
+ }
254
+ }
255
+
256
+ // Initialize on page load
257
+ document.addEventListener('DOMContentLoaded', function() {
258
+ addLog('Page loaded, ready to test WebSocket');
259
+ document.getElementById('wsUrl').textContent = getWebSocketURL();
260
+ });
261
+ </script>
262
+ </body>
263
+ </html>