- Fix SQL injection in displayprofile.asp (parameterized query) - Add HTMLEncode to XSS-vulnerable output in 5 display pages - Add Option Explicit to computers.asp, displaymachines.asp, displaypcs.asp, displayapplication.asp, displayprofile.asp - Update STANDARDS.md with test script reference, secrets management, column naming gotchas - Fix equipment type ranges in CLAUDE.md and QUICK_REFERENCE.md (1-15, 21-25) - Add migration SQL to cleanup redundant PC machinetypes (34-46) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1281 lines
31 KiB
Markdown
1281 lines
31 KiB
Markdown
# Classic ASP Development Standards
|
|
## ShopDB Application
|
|
|
|
**Version:** 1.1
|
|
**Last Updated:** 2025-12-11
|
|
**Status:** MANDATORY for all new development and modifications
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Security Standards](#security-standards)
|
|
2. [Database Access Standards](#database-access-standards)
|
|
3. [Input Validation Standards](#input-validation-standards)
|
|
4. [Output Encoding Standards](#output-encoding-standards)
|
|
5. [Error Handling Standards](#error-handling-standards)
|
|
6. [Code Structure Standards](#code-structure-standards)
|
|
7. [Naming Conventions](#naming-conventions)
|
|
8. [Documentation Standards](#documentation-standards)
|
|
9. [Performance Standards](#performance-standards)
|
|
10. [Testing Standards](#testing-standards)
|
|
|
|
---
|
|
|
|
## Security Standards
|
|
|
|
### Authentication & Authorization
|
|
|
|
**MANDATORY:** All pages MUST implement authentication checks.
|
|
|
|
```vbscript
|
|
<!--#include file="./includes/auth_check.asp"-->
|
|
<%
|
|
' This will redirect to login if user is not authenticated
|
|
Call RequireAuthentication()
|
|
|
|
' For administrative functions:
|
|
Call RequireRole("Admin")
|
|
%>
|
|
```
|
|
|
|
**Exception:** Only the following pages may skip authentication:
|
|
- `login.asp`
|
|
- `error.asp`
|
|
- `404.asp`
|
|
|
|
### Session Management
|
|
|
|
```vbscript
|
|
' Standard session configuration (in sql.asp)
|
|
Session.Timeout = APP_SESSION_TIMEOUT ' From config.asp
|
|
|
|
' After successful authentication:
|
|
Session("authenticated") = True
|
|
Session("userId") = userId
|
|
Session("userName") = userName
|
|
Session("userRole") = userRole
|
|
Session("loginTime") = Now()
|
|
Session.Abandon ' Only on explicit logout
|
|
```
|
|
|
|
### Password Requirements
|
|
|
|
- **Minimum Length:** 12 characters
|
|
- **Complexity:** Must include uppercase, lowercase, number, special character
|
|
- **Storage:** Never store plaintext passwords
|
|
- **Transmission:** HTTPS only (enforce in IIS)
|
|
|
|
### Security Headers
|
|
|
|
All pages MUST set appropriate security headers:
|
|
|
|
```vbscript
|
|
Response.AddHeader "X-Content-Type-Options", "nosniff"
|
|
Response.AddHeader "X-Frame-Options", "SAMEORIGIN"
|
|
Response.AddHeader "X-XSS-Protection", "1; mode=block"
|
|
Response.AddHeader "Content-Security-Policy", "default-src 'self'"
|
|
```
|
|
|
|
---
|
|
|
|
## Database Access Standards
|
|
|
|
### Connection String
|
|
|
|
**MANDATORY:** Use configuration file, NEVER hard-code credentials.
|
|
|
|
```vbscript
|
|
<!--#include file="./includes/config.asp"-->
|
|
<%
|
|
' In sql.asp - use config constants
|
|
objConn.ConnectionString = GetConnectionString()
|
|
objConn.Open
|
|
%>
|
|
```
|
|
|
|
### Parameterized Queries
|
|
|
|
**MANDATORY:** ALL database queries MUST use parameterization.
|
|
|
|
** NEVER DO THIS:**
|
|
```vbscript
|
|
' WRONG - SQL Injection vulnerable
|
|
machineId = Request.QueryString("machineid")
|
|
strSQL = "SELECT * FROM machines WHERE machineid = " & machineId
|
|
Set rs = objConn.Execute(strSQL)
|
|
```
|
|
|
|
** ALWAYS DO THIS:**
|
|
```vbscript
|
|
' CORRECT - Parameterized query
|
|
machineId = GetSafeInteger("QS", "machineid", 0, 1, 999999)
|
|
|
|
Set cmd = Server.CreateObject("ADODB.Command")
|
|
cmd.ActiveConnection = objConn
|
|
cmd.CommandText = "SELECT * FROM machines WHERE machineid = ?"
|
|
cmd.CommandType = 1 ' adCmdText
|
|
|
|
Set param = cmd.CreateParameter("@machineid", 3, 1, , machineId) ' 3=adInteger, 1=adParamInput
|
|
cmd.Parameters.Append param
|
|
|
|
Set rs = cmd.Execute()
|
|
```
|
|
|
|
### Resource Cleanup
|
|
|
|
**MANDATORY:** Always clean up database resources.
|
|
|
|
```vbscript
|
|
<%
|
|
' At the end of EVERY page:
|
|
Call CleanupResources()
|
|
%>
|
|
```
|
|
|
|
**Template:**
|
|
```vbscript
|
|
<!--#include file="./includes/cleanup.asp"-->
|
|
<%
|
|
On Error Resume Next
|
|
|
|
' Database operations here
|
|
|
|
' Before any Response.Redirect:
|
|
Call CleanupResources()
|
|
Response.Redirect("page.asp")
|
|
Response.End
|
|
|
|
' At end of page:
|
|
Call CleanupResources()
|
|
On Error Goto 0
|
|
%>
|
|
```
|
|
|
|
### Connection Pooling
|
|
|
|
**MANDATORY:** Enable connection pooling in configuration.
|
|
|
|
```vbscript
|
|
' In config.asp GetConnectionString() function:
|
|
connectionString = connectionString & "Pooling=True;Max Pool Size=100;"
|
|
```
|
|
|
|
---
|
|
|
|
## Input Validation Standards
|
|
|
|
### Validation Library
|
|
|
|
**MANDATORY:** Use validation functions for ALL user input.
|
|
|
|
```vbscript
|
|
<!--#include file="./includes/validation.asp"-->
|
|
```
|
|
|
|
### Common Validation Patterns
|
|
|
|
#### Integer IDs
|
|
```vbscript
|
|
Dim machineId
|
|
machineId = GetSafeInteger("QS", "machineid", 0, 1, 999999)
|
|
|
|
If machineId = 0 Then
|
|
Response.Redirect("error.asp?msg=INVALID_ID")
|
|
Response.End
|
|
End If
|
|
```
|
|
|
|
#### String Fields
|
|
```vbscript
|
|
Dim serialNumber
|
|
serialNumber = GetSafeString("FORM", "serialnumber", "", 7, 50, "^[A-Z0-9]+$")
|
|
|
|
If serialNumber = "" Then
|
|
Response.Redirect("adddevice.asp?error=INVALID_SERIAL")
|
|
Response.End
|
|
End If
|
|
```
|
|
|
|
#### IP Addresses
|
|
```vbscript
|
|
Dim ipAddress
|
|
ipAddress = Request.Form("ipaddress")
|
|
|
|
If Not ValidateIPAddress(ipAddress) Then
|
|
Response.Redirect("error.asp?msg=INVALID_IP")
|
|
Response.End
|
|
End If
|
|
```
|
|
|
|
#### Email Addresses
|
|
```vbscript
|
|
Dim email
|
|
email = Request.Form("email")
|
|
|
|
If Not ValidateEmail(email) Then
|
|
Response.Redirect("error.asp?msg=INVALID_EMAIL")
|
|
Response.End
|
|
End If
|
|
```
|
|
|
|
### Whitelist Validation
|
|
|
|
**PREFERRED:** Use whitelist validation whenever possible.
|
|
|
|
```vbscript
|
|
' Example: Only allow specific status values
|
|
Dim status
|
|
status = Request.Form("status")
|
|
|
|
If status <> "active" And status <> "inactive" And status <> "pending" Then
|
|
Response.Redirect("error.asp?msg=INVALID_STATUS")
|
|
Response.End
|
|
End If
|
|
```
|
|
|
|
### Client-Side Validation
|
|
|
|
**REQUIRED:** Implement client-side validation for user experience.
|
|
|
|
**CRITICAL:** Client-side validation does NOT replace server-side validation.
|
|
|
|
```html
|
|
<form onsubmit="return validateForm();">
|
|
<input type="text"
|
|
name="serialnumber"
|
|
id="serialnumber"
|
|
required
|
|
minlength="7"
|
|
maxlength="50"
|
|
pattern="[A-Za-z0-9]+"
|
|
title="7-50 alphanumeric characters">
|
|
</form>
|
|
|
|
<script>
|
|
function validateForm() {
|
|
var serial = document.getElementById("serialnumber").value;
|
|
if (!/^[A-Z0-9]{7,50}$/i.test(serial)) {
|
|
alert("Serial number must be 7-50 alphanumeric characters");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
</script>
|
|
```
|
|
|
|
---
|
|
|
|
## Output Encoding Standards
|
|
|
|
### HTML Output
|
|
|
|
**MANDATORY:** ALL user-controlled output MUST be HTML-encoded.
|
|
|
|
** NEVER DO THIS:**
|
|
```vbscript
|
|
<h5><%=rs("machinename")%></h5>
|
|
<p><%Response.Write(rs("description"))%></p>
|
|
```
|
|
|
|
** ALWAYS DO THIS:**
|
|
```vbscript
|
|
<h5><%=Server.HTMLEncode(rs("machinename"))%></h5>
|
|
<p><%Response.Write(Server.HTMLEncode(rs("description")))%></p>
|
|
```
|
|
|
|
### JavaScript Context
|
|
|
|
**MANDATORY:** Use JavaScript encoding for data in JavaScript.
|
|
|
|
```vbscript
|
|
<script>
|
|
var machineName = "<%=JavaScriptEncode(rs("machinename"))%>";
|
|
</script>
|
|
```
|
|
|
|
```vbscript
|
|
' Helper function in includes/encoding.asp
|
|
Function JavaScriptEncode(str)
|
|
Dim result
|
|
result = Replace(str, "\", "\\")
|
|
result = Replace(result, "'", "\'")
|
|
result = Replace(result, """", "\""")
|
|
result = Replace(result, vbCrLf, "\n")
|
|
result = Replace(result, vbCr, "\n")
|
|
result = Replace(result, vbLf, "\n")
|
|
JavaScriptEncode = result
|
|
End Function
|
|
```
|
|
|
|
### URL Parameters
|
|
|
|
**MANDATORY:** Use URLEncode for URL parameters.
|
|
|
|
```vbscript
|
|
<a href="displaymachine.asp?name=<%=Server.URLEncode(rs("machinename"))%>">Link</a>
|
|
```
|
|
|
|
### JSON Output
|
|
|
|
**MANDATORY:** Properly escape JSON output.
|
|
|
|
```vbscript
|
|
<!--#include file="./includes/json_helper.asp"-->
|
|
<%
|
|
Response.ContentType = "application/json"
|
|
Response.Write(CreateJSONFromRecordset(rs))
|
|
%>
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling Standards
|
|
|
|
### Standard Error Handler
|
|
|
|
**MANDATORY:** Include error handler in ALL pages.
|
|
|
|
```vbscript
|
|
<!--#include file="./includes/error_handler.asp"-->
|
|
<%
|
|
Call InitializeErrorHandling("pagename.asp")
|
|
|
|
' Page logic here
|
|
|
|
Call CheckForErrors() ' After each critical operation
|
|
|
|
Call CleanupResources()
|
|
%>
|
|
```
|
|
|
|
### Error Logging
|
|
|
|
**MANDATORY:** Log all errors to server-side log file.
|
|
|
|
```vbscript
|
|
' In error_handler.asp
|
|
Call LogError(pageName, Err.Number, Err.Description, Request.ServerVariables("REMOTE_ADDR"))
|
|
```
|
|
|
|
**Log Format:**
|
|
```
|
|
2025-10-10 14:35:22 | displaymachine.asp | -2147467259 | Syntax error in SQL | 192.168.122.1
|
|
```
|
|
|
|
### User-Facing Error Messages
|
|
|
|
**MANDATORY:** NEVER expose technical details to users.
|
|
|
|
** WRONG:**
|
|
```vbscript
|
|
Response.Write("Error: " & Err.Description)
|
|
```
|
|
|
|
** CORRECT:**
|
|
```vbscript
|
|
Response.Redirect("error.asp?code=DATABASE_ERROR")
|
|
```
|
|
|
|
### Error Codes
|
|
|
|
Standard error codes for user messaging:
|
|
|
|
- `INVALID_INPUT` - User input validation failed
|
|
- `NOT_FOUND` - Record not found
|
|
- `UNAUTHORIZED` - User lacks permission
|
|
- `DATABASE_ERROR` - Database operation failed
|
|
- `GENERAL_ERROR` - Catch-all for unexpected errors
|
|
|
|
---
|
|
|
|
## Code Structure Standards
|
|
|
|
### File Header
|
|
|
|
**MANDATORY:** Every ASP file must have a header comment block.
|
|
|
|
```vbscript
|
|
<%
|
|
'=============================================================================
|
|
' FILE: displaymachine.asp
|
|
' PURPOSE: Display detailed information for a single machine
|
|
'
|
|
' PARAMETERS:
|
|
' machineid (QueryString, Required) - Integer ID of machine to display
|
|
'
|
|
' DEPENDENCIES:
|
|
' - includes/config.asp - Application configuration
|
|
' - includes/sql.asp - Database connection
|
|
' - includes/validation.asp - Input validation functions
|
|
' - includes/auth_check.asp - Authentication verification
|
|
'
|
|
' DATABASE TABLES:
|
|
' - machines (primary)
|
|
' - machinetypes, models, vendors, businessunits
|
|
' - printers (LEFT JOIN - may be NULL)
|
|
' - communications (LEFT JOIN - may be NULL)
|
|
'
|
|
' SECURITY:
|
|
' - Requires authentication
|
|
' - No special role required (read-only)
|
|
' - Uses parameterized queries
|
|
'
|
|
' AUTHOR: [Your Name]
|
|
' CREATED: 2025-10-10
|
|
' MODIFIED: 2025-10-10 - Initial version
|
|
'
|
|
'=============================================================================
|
|
%>
|
|
```
|
|
|
|
### Standard Page Template
|
|
|
|
```vbscript
|
|
<%@ Language=VBScript %>
|
|
<%
|
|
Option Explicit ' MANDATORY - Forces variable declaration
|
|
%>
|
|
<!--#include file="./includes/config.asp"-->
|
|
<!--#include file="./includes/sql.asp"-->
|
|
<!--#include file="./includes/validation.asp"-->
|
|
<!--#include file="./includes/auth_check.asp"-->
|
|
<!--#include file="./includes/error_handler.asp"-->
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<!--#include file="./includes/header.asp"-->
|
|
<title>Page Title</title>
|
|
</head>
|
|
<%
|
|
'-----------------------------------------------------------------------------
|
|
' AUTHENTICATION
|
|
'-----------------------------------------------------------------------------
|
|
Call RequireAuthentication()
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' INITIALIZATION
|
|
'-----------------------------------------------------------------------------
|
|
Call InitializeErrorHandling("pagename.asp")
|
|
|
|
' Get and validate parameters
|
|
Dim paramId
|
|
paramId = GetSafeInteger("QS", "id", 0, 1, 999999)
|
|
|
|
If paramId = 0 Then
|
|
Call CleanupResources()
|
|
Response.Redirect("error.asp?msg=INVALID_ID")
|
|
Response.End
|
|
End If
|
|
|
|
' Get theme preference
|
|
Dim theme
|
|
theme = Request.Cookies("theme")
|
|
If theme = "" Then theme = "bg-theme1"
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' DATABASE OPERATIONS
|
|
'-----------------------------------------------------------------------------
|
|
Dim strSQL, objRS
|
|
|
|
strSQL = "SELECT * FROM tablename WHERE id = ?"
|
|
Set objRS = ExecuteParameterizedQuery(objConn, strSQL, Array(paramId))
|
|
Call CheckForErrors()
|
|
|
|
If objRS.EOF Then
|
|
Call CleanupResources()
|
|
Response.Redirect("error.asp?msg=NOT_FOUND")
|
|
Response.End
|
|
End If
|
|
%>
|
|
|
|
<body class="bg-theme <%=theme%>">
|
|
|
|
<div id="wrapper">
|
|
<!--#include file="./includes/leftsidebar.asp"-->
|
|
<!--#include file="./includes/topbarheader.asp"-->
|
|
|
|
<div class="clearfix"></div>
|
|
|
|
<div class="content-wrapper">
|
|
<div class="container-fluid">
|
|
|
|
<!-- Page Content -->
|
|
<h5><%=Server.HTMLEncode(objRS("name"))%></h5>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!--#include file="./includes/footer.asp"-->
|
|
</div>
|
|
|
|
<!-- JavaScript -->
|
|
<script src="assets/js/jquery.min.js"></script>
|
|
<script src="assets/js/bootstrap.min.js"></script>
|
|
<script src="assets/js/app-script.js"></script>
|
|
|
|
</body>
|
|
</html>
|
|
|
|
<%
|
|
'-----------------------------------------------------------------------------
|
|
' CLEANUP
|
|
'-----------------------------------------------------------------------------
|
|
Call CleanupResources()
|
|
%>
|
|
```
|
|
|
|
### Form Processing Template
|
|
|
|
```vbscript
|
|
<%@ Language=VBScript %>
|
|
<%
|
|
Option Explicit
|
|
%>
|
|
<!--#include file="./includes/config.asp"-->
|
|
<!--#include file="./includes/sql.asp"-->
|
|
<!--#include file="./includes/validation.asp"-->
|
|
<!--#include file="./includes/auth_check.asp"-->
|
|
<!--#include file="./includes/error_handler.asp"-->
|
|
<%
|
|
'-----------------------------------------------------------------------------
|
|
' AUTHENTICATION
|
|
'-----------------------------------------------------------------------------
|
|
Call RequireAuthentication()
|
|
Call RequireRole("Editor") ' If write operation requires special role
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' INITIALIZATION
|
|
'-----------------------------------------------------------------------------
|
|
Call InitializeErrorHandling("savepage.asp")
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' VALIDATE INPUT
|
|
'-----------------------------------------------------------------------------
|
|
Dim recordId, fieldValue1, fieldValue2
|
|
|
|
recordId = GetSafeInteger("FORM", "id", 0, 0, 999999)
|
|
fieldValue1 = GetSafeString("FORM", "field1", "", 1, 100, "^[A-Za-z0-9 ]+$")
|
|
fieldValue2 = GetSafeString("FORM", "field2", "", 0, 200, "")
|
|
|
|
If fieldValue1 = "" Then
|
|
Call CleanupResources()
|
|
Response.Redirect("editpage.asp?id=" & recordId & "&error=REQUIRED_FIELD")
|
|
Response.End
|
|
End If
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' DATABASE OPERATION
|
|
'-----------------------------------------------------------------------------
|
|
Dim strSQL
|
|
|
|
If recordId > 0 Then
|
|
' Update existing record
|
|
strSQL = "UPDATE tablename SET field1 = ?, field2 = ?, lastupdated = NOW() WHERE id = ?"
|
|
Call ExecuteParameterizedUpdate(objConn, strSQL, Array(fieldValue1, fieldValue2, recordId))
|
|
Else
|
|
' Insert new record
|
|
strSQL = "INSERT INTO tablename (field1, field2, created) VALUES (?, ?, NOW())"
|
|
Call ExecuteParameterizedInsert(objConn, strSQL, Array(fieldValue1, fieldValue2))
|
|
recordId = CLng(objConn.Execute("SELECT LAST_INSERT_ID() AS id")(0))
|
|
End If
|
|
|
|
Call CheckForErrors()
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' CLEANUP AND REDIRECT
|
|
'-----------------------------------------------------------------------------
|
|
Call CleanupResources()
|
|
Response.Redirect("displaypage.asp?id=" & recordId & "&success=1")
|
|
%>
|
|
```
|
|
|
|
---
|
|
|
|
## Naming Conventions
|
|
|
|
### Variables
|
|
|
|
**Style:** camelCase
|
|
|
|
```vbscript
|
|
' IDs - use "Id" suffix
|
|
Dim machineId, printerId, userId
|
|
|
|
' Strings - descriptive names
|
|
Dim serialNumber, ipAddress, userName, description
|
|
|
|
' Booleans - use "is" or "has" prefix
|
|
Dim isActive, hasPermission, isValid
|
|
|
|
' Database objects - use obj prefix
|
|
Dim objConn, objCmd, objRS
|
|
|
|
' SQL queries - use str prefix
|
|
Dim strSQL, strSQL2
|
|
|
|
' Counters/indexes - single letter or descriptive
|
|
Dim i, j, rowCount, itemIndex
|
|
```
|
|
|
|
### Constants
|
|
|
|
**Style:** UPPER_CASE_WITH_UNDERSCORES
|
|
|
|
```vbscript
|
|
Const DB_SERVER = "192.168.122.1"
|
|
Const MAX_FILE_SIZE = 10485760
|
|
Const SESSION_TIMEOUT = 30
|
|
Const DEFAULT_PAGE_SIZE = 50
|
|
```
|
|
|
|
### Functions
|
|
|
|
**Style:** PascalCase, verb-noun format
|
|
|
|
```vbscript
|
|
Function GetMachineById(machineId)
|
|
Function ValidateIPAddress(ipAddress)
|
|
Function RenderVendorDropdown(selectedId, filterType)
|
|
Function CreateJSONResponse(success, message, data)
|
|
Function CalculateTotalCost(items)
|
|
```
|
|
|
|
### Subroutines
|
|
|
|
**Style:** PascalCase, verb-noun format
|
|
|
|
```vbscript
|
|
Sub InitializeErrorHandling(pageName)
|
|
Sub CleanupResources()
|
|
Sub RequireAuthentication()
|
|
Sub LogError(source, errorNum, errorDesc)
|
|
```
|
|
|
|
### Files
|
|
|
|
**Display Pages (single record):** display[noun-singular].asp
|
|
- `displaymachine.asp`
|
|
- `displayprinter.asp`
|
|
- `displaypc.asp`
|
|
|
|
**List Pages (multiple records):** display[noun-plural].asp
|
|
- `displaymachines.asp`
|
|
- `displayprinters.asp`
|
|
- `displaypcs.asp`
|
|
|
|
**Edit Pages:** edit[noun-singular].asp
|
|
- `editmachine.asp`
|
|
- `editprinter.asp`
|
|
- `editpc.asp`
|
|
|
|
**Add Pages:** add[noun-singular].asp
|
|
- `addmachine.asp`
|
|
- `addprinter.asp`
|
|
- `addpc.asp`
|
|
|
|
**Form Processors:** [verb][noun].asp
|
|
- `savemachine.asp`
|
|
- `updatemachine.asp`
|
|
- `deletemachine.asp`
|
|
|
|
**Include Files:** descriptive lowercase
|
|
- `sql.asp`
|
|
- `config.asp`
|
|
- `validation.asp`
|
|
- `error_handler.asp`
|
|
- `auth_check.asp`
|
|
|
|
### Database Tables
|
|
|
|
**Style:** lowercase, plural nouns
|
|
|
|
```sql
|
|
machines -- Unified table: Equipment, PCs, Network Devices
|
|
printers
|
|
communications -- Network interfaces (IP/MAC)
|
|
machinetypes
|
|
vendors
|
|
models
|
|
```
|
|
|
|
### Database Columns
|
|
|
|
**Style:** lowercase, descriptive
|
|
|
|
```sql
|
|
machineid
|
|
machinenumber
|
|
serialnumber
|
|
ipaddress
|
|
isactive
|
|
createdate
|
|
lastupdated
|
|
```
|
|
|
|
### Column Naming Gotchas
|
|
|
|
**IMPORTANT:** Be aware of these non-obvious column names:
|
|
|
|
| Expected | Actual | Table |
|
|
|----------|--------|-------|
|
|
| `ipaddress` | `address` | communications |
|
|
| `gateway` | `defaultgateway` | communications |
|
|
| `notes` | `machinenotes` | machines |
|
|
| `pcid` | `machineid` | machines (PCs are in unified table) |
|
|
| `pc_comm_config` | `commconfig` | (table name) |
|
|
| `pc_dnc_config` | `dncconfig` | (table name) |
|
|
|
|
**PC Identification:** PCs are in the `machines` table, identified by:
|
|
- `pctypeid IS NOT NULL`
|
|
- `machinetypeid IN (33, 34, 35)`
|
|
|
|
---
|
|
|
|
## Documentation Standards
|
|
|
|
### Inline Comments
|
|
|
|
**REQUIRED:** Comment complex logic and business rules.
|
|
|
|
```vbscript
|
|
'-----------------------------------------------------------------------------
|
|
' Search Logic:
|
|
' 1. Check if input matches machine number (exact) or alias (partial)
|
|
' 2. If starts with "csf" and length=5, search printer CSF names
|
|
' 3. If 7 alphanumeric chars, treat as PC serial number
|
|
' 4. If valid IP, find containing subnet
|
|
' 5. If 9 digits, treat as SSO employee number
|
|
' 6. If starts with ticket prefix, redirect to ServiceNow
|
|
' 7. Otherwise, full-text search knowledge base
|
|
'-----------------------------------------------------------------------------
|
|
```
|
|
|
|
### SQL Query Comments
|
|
|
|
**RECOMMENDED:** Document complex queries.
|
|
|
|
```vbscript
|
|
'-----------------------------------------------------------------------------
|
|
' QUERY: Get machine with all related data
|
|
'
|
|
' Retrieves:
|
|
' - Machine details (machines table)
|
|
' - Type and function account (for billing)
|
|
' - Model and vendor information
|
|
' - Business unit assignment
|
|
' - Associated printer (LEFT JOIN - may be NULL)
|
|
' - Associated PC (LEFT JOIN - may be NULL)
|
|
'
|
|
' LEFT JOINs used because not all machines have printers/PCs.
|
|
'-----------------------------------------------------------------------------
|
|
strSQL = "SELECT m.*, mt.machinetype, mdl.modelnumber, " & _
|
|
" v.vendor, bu.businessunit, " & _
|
|
" p.ipaddress AS printerip " & _
|
|
"FROM machines m " & _
|
|
"INNER JOIN machinetypes mt ON m.machinetypeid = mt.machinetypeid " & _
|
|
"LEFT JOIN printers p ON m.printerid = p.printerid " & _
|
|
"WHERE m.machineid = ?"
|
|
```
|
|
|
|
### Function Documentation
|
|
|
|
**MANDATORY:** Document all functions and subroutines.
|
|
|
|
```vbscript
|
|
'-----------------------------------------------------------------------------
|
|
' FUNCTION: ValidateIPAddress
|
|
' PURPOSE: Validates that a string is a valid IPv4 address
|
|
'
|
|
' PARAMETERS:
|
|
' ipAddress (String) - The IP address to validate
|
|
'
|
|
' RETURNS:
|
|
' Boolean - True if valid IPv4 address, False otherwise
|
|
'
|
|
' EXAMPLES:
|
|
' ValidateIPAddress("192.168.1.1") -> True
|
|
' ValidateIPAddress("192.168.1.256") -> False
|
|
' ValidateIPAddress("not an ip") -> False
|
|
'
|
|
' VALIDATION:
|
|
' - Must match pattern: XXX.XXX.XXX.XXX
|
|
' - Each octet must be 0-255
|
|
' - No leading zeros allowed
|
|
'-----------------------------------------------------------------------------
|
|
Function ValidateIPAddress(ipAddress)
|
|
Dim objRegEx, pattern
|
|
Set objRegEx = New RegExp
|
|
pattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
|
|
objRegEx.Pattern = pattern
|
|
ValidateIPAddress = objRegEx.Test(ipAddress)
|
|
End Function
|
|
```
|
|
|
|
### TODO Comments
|
|
|
|
**ENCOURAGED:** Use standardized TODO format.
|
|
|
|
```vbscript
|
|
' TODO: SECURITY - Add authentication check (HIGH PRIORITY)
|
|
' TODO: PERFORMANCE - Cache this query result
|
|
' TODO: VALIDATION - Add email format validation
|
|
' TODO: REFACTOR - Extract to reusable function
|
|
' TODO: BUG - Handle null value edge case
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Standards
|
|
|
|
### Database Query Optimization
|
|
|
|
**REQUIRED:** Follow these query optimization practices.
|
|
|
|
#### Use Specific Columns
|
|
```vbscript
|
|
' BAD
|
|
strSQL = "SELECT * FROM machines"
|
|
|
|
' GOOD
|
|
strSQL = "SELECT machineid, machinenumber, machinetype FROM machines"
|
|
```
|
|
|
|
#### Use Appropriate JOINs
|
|
```vbscript
|
|
' Use INNER JOIN when relationship is required
|
|
' Use LEFT JOIN when relationship is optional
|
|
' Avoid RIGHT JOIN (use LEFT JOIN instead for clarity)
|
|
```
|
|
|
|
#### Limit Result Sets
|
|
```vbscript
|
|
' For list views, always implement paging
|
|
strSQL = "SELECT * FROM machines WHERE isactive = 1 " & _
|
|
"ORDER BY machinenumber " & _
|
|
"LIMIT " & pageSize & " OFFSET " & offset
|
|
```
|
|
|
|
### Caching Strategy
|
|
|
|
**REQUIRED:** Cache reference data at application scope.
|
|
|
|
```vbscript
|
|
' In global.asa Application_OnStart
|
|
Sub Application_OnStart
|
|
' Cache rarely-changing reference data
|
|
Call LoadVendorCache()
|
|
Call LoadModelCache()
|
|
Call LoadMachineTypeCache()
|
|
End Sub
|
|
|
|
' In data_cache.asp
|
|
Function GetCachedVendors()
|
|
If IsEmpty(Application("CachedVendors")) Or _
|
|
DateDiff("s", Application("VendorCacheTime"), Now()) > CACHE_DURATION Then
|
|
Call LoadVendorCache()
|
|
End If
|
|
GetCachedVendors = Application("CachedVendors")
|
|
End Function
|
|
```
|
|
|
|
**Cache Invalidation:**
|
|
- Time-based: 5-30 minutes for reference data
|
|
- Event-based: Invalidate when data is modified
|
|
- Manual: Provide admin function to clear cache
|
|
|
|
### Response Buffering
|
|
|
|
**REQUIRED:** Enable response buffering.
|
|
|
|
```vbscript
|
|
<%
|
|
Response.Buffer = True
|
|
%>
|
|
```
|
|
|
|
**Benefits:**
|
|
- Allows headers to be set after content generation
|
|
- Enables proper error handling with redirects
|
|
- Improves performance by sending larger chunks
|
|
|
|
### Minimize Database Roundtrips
|
|
|
|
**PREFERRED:** Consolidate queries when possible.
|
|
|
|
```vbscript
|
|
' BAD - 4 separate queries
|
|
Set rsVendors = objConn.Execute("SELECT * FROM vendors")
|
|
Set rsModels = objConn.Execute("SELECT * FROM models")
|
|
Set rsTypes = objConn.Execute("SELECT * FROM machinetypes")
|
|
Set rsUnits = objConn.Execute("SELECT * FROM businessunits")
|
|
|
|
' BETTER - Use cached data
|
|
Response.Write(RenderCachedVendorDropdown())
|
|
Response.Write(RenderCachedModelDropdown())
|
|
Response.Write(RenderCachedTypeDropdown())
|
|
Response.Write(RenderCachedUnitDropdown())
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Standards
|
|
|
|
### Automated Form Testing
|
|
|
|
**REQUIRED:** Run the comprehensive test suite after making changes to ASP pages.
|
|
|
|
```bash
|
|
./tests/test_forms.sh
|
|
```
|
|
|
|
This script tests 41 endpoints including:
|
|
- Page load tests (dashboards, list views, maps)
|
|
- Add form page loads
|
|
- Form submissions (notifications, equipment, printers, subnets, applications, KB, vendors, models, network devices)
|
|
- API endpoints
|
|
|
|
Test data uses `AUTOTEST_` prefix for easy cleanup. See `tests/cleanup_test_data.sql`.
|
|
|
|
### Unit Testing
|
|
|
|
**REQUIRED:** Test all validation functions.
|
|
|
|
Create test file: `tests/test_validation.asp`
|
|
|
|
```vbscript
|
|
<!--#include file="../includes/validation.asp"-->
|
|
<%
|
|
Sub TestValidateIPAddress()
|
|
If ValidateIPAddress("192.168.1.1") Then
|
|
Response.Write("PASS: Valid IP accepted<br>")
|
|
Else
|
|
Response.Write("FAIL: Valid IP rejected<br>")
|
|
End If
|
|
|
|
If Not ValidateIPAddress("999.999.999.999") Then
|
|
Response.Write("PASS: Invalid IP rejected<br>")
|
|
Else
|
|
Response.Write("FAIL: Invalid IP accepted<br>")
|
|
End If
|
|
End Sub
|
|
|
|
Call TestValidateIPAddress()
|
|
%>
|
|
```
|
|
|
|
### Integration Testing
|
|
|
|
**RECOMMENDED:** Test critical user flows.
|
|
|
|
**Test Cases:**
|
|
1. User login flow
|
|
2. Machine creation flow
|
|
3. Machine update flow
|
|
4. Search functionality
|
|
5. Report generation
|
|
|
|
### Security Testing
|
|
|
|
**REQUIRED:** Test for common vulnerabilities.
|
|
|
|
**Test Checklist:**
|
|
- [ ] SQL injection attempts on all input fields
|
|
- [ ] XSS payloads in all text fields
|
|
- [ ] Access control bypass attempts
|
|
- [ ] Session hijacking scenarios
|
|
- [ ] CSRF token validation
|
|
|
|
### Load Testing
|
|
|
|
**RECOMMENDED:** Test under expected load.
|
|
|
|
**Metrics to Monitor:**
|
|
- Response time per page
|
|
- Database connection pool usage
|
|
- Memory consumption
|
|
- Concurrent user capacity
|
|
|
|
---
|
|
|
|
## Code Review Checklist
|
|
|
|
Before committing code, verify:
|
|
|
|
### Security
|
|
- [ ] Authentication check present
|
|
- [ ] All queries use parameterization
|
|
- [ ] All output is HTML-encoded
|
|
- [ ] Input validation implemented
|
|
- [ ] No credentials in code
|
|
|
|
### Error Handling
|
|
- [ ] Error handler included
|
|
- [ ] Resources cleaned up on all paths
|
|
- [ ] No technical details exposed to users
|
|
- [ ] Errors logged to server
|
|
|
|
### Code Quality
|
|
- [ ] File header present
|
|
- [ ] Complex logic commented
|
|
- [ ] Naming conventions followed
|
|
- [ ] No code duplication
|
|
- [ ] No commented-out debug code
|
|
|
|
### Performance
|
|
- [ ] Queries optimized
|
|
- [ ] Appropriate caching used
|
|
- [ ] Resources properly closed
|
|
- [ ] Result sets limited/paged
|
|
|
|
### Testing
|
|
- [ ] Manually tested happy path
|
|
- [ ] Tested error conditions
|
|
- [ ] Tested with invalid input
|
|
- [ ] Cross-browser tested (if UI changes)
|
|
|
|
---
|
|
|
|
## Configuration Management
|
|
|
|
### Environment-Specific Configurations
|
|
|
|
**Structure:**
|
|
```
|
|
/includes/
|
|
config.asp.template (Template with placeholders)
|
|
config.dev.asp (Development settings)
|
|
config.test.asp (Testing settings)
|
|
config.prod.asp (Production settings)
|
|
```
|
|
|
|
**Deployment Process:**
|
|
1. Copy appropriate config file to `config.asp`
|
|
2. Never commit `config.asp` to source control
|
|
3. Add `config.asp` to `.gitignore`
|
|
|
|
### Secrets Management
|
|
|
|
**MANDATORY:** Store sensitive credentials in `secrets.md` (gitignored).
|
|
|
|
**Contents:**
|
|
- Zabbix API URL and token
|
|
- Gitea API URL and token
|
|
- Database credentials (per environment)
|
|
|
|
**NEVER commit:**
|
|
- API tokens
|
|
- Database passwords
|
|
- Authentication credentials
|
|
|
|
### Configuration Template
|
|
|
|
```vbscript
|
|
<%
|
|
'=============================================================================
|
|
' Application Configuration
|
|
' IMPORTANT: Copy this to config.asp and update values for your environment
|
|
'=============================================================================
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' Database Configuration
|
|
'-----------------------------------------------------------------------------
|
|
Const DB_DRIVER = "MySQL ODBC 9.4 Unicode Driver"
|
|
Const DB_SERVER = "192.168.122.1"
|
|
Const DB_PORT = "3306"
|
|
Const DB_NAME = "shopdb"
|
|
Const DB_USER = "appuser"
|
|
Const DB_PASSWORD = "CHANGE_THIS_PASSWORD"
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' Application Settings
|
|
'-----------------------------------------------------------------------------
|
|
Const APP_SESSION_TIMEOUT = 30
|
|
Const APP_PAGE_SIZE = 50
|
|
Const APP_CACHE_DURATION = 300 ' seconds
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' Business Logic Configuration
|
|
'-----------------------------------------------------------------------------
|
|
Const SERIAL_NUMBER_LENGTH = 7
|
|
Const SSO_NUMBER_LENGTH = 9
|
|
Const CSF_PREFIX = "csf"
|
|
Const CSF_LENGTH = 5
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' Default Values
|
|
'-----------------------------------------------------------------------------
|
|
Const DEFAULT_PC_STATUS_ID = 2
|
|
Const DEFAULT_MODEL_ID = 1
|
|
Const DEFAULT_OS_ID = 1
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' External Services
|
|
'-----------------------------------------------------------------------------
|
|
Const SNOW_BASE_URL = "https://geit.service-now.com/now/nav/ui/search/"
|
|
Const ZABBIX_API_URL = "http://zabbix.example.com/api_jsonrpc.php"
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' File Upload
|
|
'-----------------------------------------------------------------------------
|
|
Const MAX_FILE_SIZE = 10485760 ' 10MB
|
|
Const ALLOWED_EXTENSIONS = "jpg,jpeg,png,gif,pdf"
|
|
|
|
'-----------------------------------------------------------------------------
|
|
' Helper Functions
|
|
'-----------------------------------------------------------------------------
|
|
Function GetConnectionString()
|
|
GetConnectionString = "Driver={" & DB_DRIVER & "};" & _
|
|
"Server=" & DB_SERVER & ";" & _
|
|
"Port=" & DB_PORT & ";" & _
|
|
"Database=" & DB_NAME & ";" & _
|
|
"User=" & DB_USER & ";" & _
|
|
"Password=" & DB_PASSWORD & ";" & _
|
|
"Option=3;" & _
|
|
"Pooling=True;Max Pool Size=100;"
|
|
End Function
|
|
%>
|
|
```
|
|
|
|
---
|
|
|
|
## Migration Guide
|
|
|
|
### Updating Existing Files to Meet Standards
|
|
|
|
**Priority Order:**
|
|
1. Add authentication check
|
|
2. Fix SQL injection vulnerabilities
|
|
3. Add HTML encoding to output
|
|
4. Add error handling
|
|
5. Add file header documentation
|
|
6. Refactor for code quality
|
|
|
|
### Example Migration
|
|
|
|
**Before (Non-Compliant):**
|
|
```vbscript
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head><title>Machine</title></head>
|
|
<body>
|
|
<%
|
|
machineid = Request.QueryString("machineid")
|
|
strSQL = "SELECT * FROM machines WHERE machineid = " & machineid
|
|
set rs = objconn.Execute(strSQL)
|
|
%>
|
|
<h1><%=rs("machinename")%></h1>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
**After (Standards-Compliant):**
|
|
```vbscript
|
|
<%@ Language=VBScript %>
|
|
<%
|
|
Option Explicit
|
|
%>
|
|
<!--#include file="./includes/config.asp"-->
|
|
<!--#include file="./includes/sql.asp"-->
|
|
<!--#include file="./includes/validation.asp"-->
|
|
<!--#include file="./includes/auth_check.asp"-->
|
|
<!--#include file="./includes/error_handler.asp"-->
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<!--#include file="./includes/header.asp"-->
|
|
<title>Machine Details</title>
|
|
</head>
|
|
<%
|
|
'-----------------------------------------------------------------------------
|
|
' FILE: displaymachine.asp
|
|
' PURPOSE: Display machine details
|
|
'-----------------------------------------------------------------------------
|
|
|
|
Call RequireAuthentication()
|
|
Call InitializeErrorHandling("displaymachine.asp")
|
|
|
|
Dim machineId, strSQL, objRS
|
|
|
|
machineId = GetSafeInteger("QS", "machineid", 0, 1, 999999)
|
|
If machineId = 0 Then
|
|
Call CleanupResources()
|
|
Response.Redirect("error.asp?msg=INVALID_ID")
|
|
Response.End
|
|
End If
|
|
|
|
strSQL = "SELECT * FROM machines WHERE machineid = ?"
|
|
Set objRS = ExecuteParameterizedQuery(objConn, strSQL, Array(machineId))
|
|
Call CheckForErrors()
|
|
|
|
If objRS.EOF Then
|
|
Call CleanupResources()
|
|
Response.Redirect("error.asp?msg=NOT_FOUND")
|
|
Response.End
|
|
End If
|
|
%>
|
|
<body>
|
|
<h1><%=Server.HTMLEncode(objRS("machinename"))%></h1>
|
|
</body>
|
|
</html>
|
|
<%
|
|
Call CleanupResources()
|
|
%>
|
|
```
|
|
|
|
---
|
|
|
|
## Enforcement
|
|
|
|
### Code Review Process
|
|
|
|
**MANDATORY:** All code changes must be reviewed before deployment.
|
|
|
|
**Reviewer Checklist:**
|
|
1. Standards compliance verified
|
|
2. Security vulnerabilities checked
|
|
3. Performance impact assessed
|
|
4. Documentation adequate
|
|
5. Tests passed
|
|
|
|
### Automated Checks
|
|
|
|
**RECOMMENDED:** Implement automated scanning where possible.
|
|
|
|
**Tools:**
|
|
- SQL injection scanner
|
|
- XSS vulnerability scanner
|
|
- Code style checker
|
|
- Dead code detector
|
|
|
|
### Training
|
|
|
|
**REQUIRED:** All developers must:
|
|
1. Read this standards document
|
|
2. Complete security training
|
|
3. Review example compliant code
|
|
4. Pass knowledge assessment
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Date | Changes | Author |
|
|
|---------|------|---------|--------|
|
|
| 1.0 | 2025-10-10 | Initial standards document created from audit findings | Claude |
|
|
| 1.1 | 2025-12-11 | Updated for Phase 2 schema (unified machines table), added test script reference, secrets management, column naming gotchas | Claude |
|
|
|
|
---
|
|
|
|
## Questions & Support
|
|
|
|
For questions about these standards:
|
|
1. Review the examples in this document
|
|
2. Check existing compliant code for patterns
|
|
3. Consult with team lead
|
|
4. Document unclear areas for future clarification
|
|
|
|
---
|
|
|
|
**REMEMBER:** These standards exist to protect our application and data. Following them is not optional—it's a requirement for all development work.
|