Files
shopdb/displayapplication.asp
cproudlock e0d89f9957 Security fixes and schema cleanup
- 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>
2025-12-12 07:22:16 -05:00

614 lines
30 KiB
Plaintext

<%@ Language=VBScript %>
<%
Option Explicit
%>
<!--#include file="./includes/sql.asp"-->
<%
Dim appid, rs
appid = Request.Querystring("appid")
' Basic validation - must be numeric and positive
If Not IsNumeric(appid) Or CLng(appid) < 1 Then
Response.Redirect("displayapplications.asp")
Response.End
End If
appid = CLng(appid) ' Convert to long integer
Dim theme
theme = Request.Cookies("theme")
IF theme = "" THEN
theme="bg-theme1"
END IF
' Simple query with validated integer
Dim strSQL
strSQL = "SELECT a.*, s.teamname, s.teamurl, o.appowner, o.sso " & _
"FROM applications a " & _
"INNER JOIN supportteams s ON a.supportteamid = s.supporteamid " & _
"INNER JOIN appowners o ON s.appownerid = o.appownerid " & _
"WHERE a.appid = " & appid
set rs = objconn.Execute(strSQL)
If rs.EOF Then
Response.Redirect("displayapplications.asp")
objConn.Close
Response.End
End If
%>
<!DOCTYPE html>
<html lang="en">
<head>
<!--#include file="./includes/header.asp"-->
</head>
<body class="bg-theme <%Response.Write(theme)%>">
<!-- start loader -->
<div id="pageloader-overlay" class="visible incoming"><div class="loader-wrapper-outer"><div class="loader-wrapper-inner" ><div class="loader"></div></div></div></div>
<!-- end loader -->
<!-- Start wrapper-->
<div id="wrapper">
<!--#include file="./includes/leftsidebar.asp"-->
<!--Start topbar header-->
<!--#include file="./includes/topbarheader.asp"-->
<!--End topbar header-->
<div class="clearfix"></div>
<div class="content-wrapper">
<div class="container-fluid">
<div class="row mt-3">
<div class="col-lg-4">
<div class="card profile-card-2">
<div class="card-img-block">
<img class="img-fluid" src="./images/applications/<%=Server.HTMLEncode(rs("image") & "")%>" alt="Card image cap">
</div>
<div class="card-body pt-5">
<img src="./images/applications/<%=Server.HTMLEncode(rs("image") & "")%>" alt="profile-image" class="profile">
<h5 class="card-title"></h5>
<p class="card-text"><a href="" title="Click to Access Support Docs" target="_blank"></a></p>
</div>
<div class="card-body border-top border-light">
<div class="media align-items-center">
</div>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="card">
<div class="card-body">
<ul class="nav nav-tabs nav-tabs-primary top-icon nav-justified">
<li class="nav-item">
<a href="javascript:void();" data-target="#profile" data-toggle="pill" class="nav-link active"><i class="icon-wrench"></i> <span class="hidden-xs">Settings</span></a>
</li>
<li class="nav-item">
<a href="javascript:void();" data-target="#edit" data-toggle="pill" class="nav-link"><i class="zmdi zmdi-edit"></i> <span class="hidden-xs">Edit</span></a>
</li>
</ul>
<div class="tab-content p-3">
<div class="tab-pane active" id="profile">
<h5 class="mb-3"><%=Server.HTMLEncode(rs("appname") & "")%></h5>
<div class="row">
<div class="col-md-3">
<p class="mb-2"><strong>Support Team:</strong></p>
<p class="mb-2"><strong>App Owner:</strong></p>
<p class="mb-2"><strong>SSO:</strong></p>
<%
Dim installPath, docPath, appLink
installPath = rs("installpath") & ""
appLink = rs("applicationlink") & ""
docPath = rs("documentationpath") & ""
If appLink <> "" Then
Response.Write("<p class='mb-2'><strong>Application Link:</strong></p>")
End If
If installPath <> "" Then
Response.Write("<p class='mb-2'><strong>Installation Files:</strong></p>")
End If
If docPath <> "" Then
Response.Write("<p class='mb-2'><strong>Documentation:</strong></p>")
End If
%>
</div>
<div class="col-md-8">
<%
Dim teamUrl
teamUrl = rs("teamurl") & ""
If teamUrl <> "" Then
Response.Write("<p class='mb-2'><a href='" & Server.HTMLEncode(teamUrl) & "' target='_blank' title='Click here for Service Now page'>" & Server.HTMLEncode(rs("teamname")) & "</a></p>")
Else
Response.Write("<p class='mb-2'>" & Server.HTMLEncode(rs("teamname")) & "</p>")
End If
%>
<p class="mb-2"><a href="msteams:/l/chat/0/0?users=<%=Server.HTMLEncode(rs("sso") & "")%>@geaerospace.com" title="Click here for Teams Chat"><%=Server.HTMLEncode(rs("appowner") & "")%></a></p>
<p class="mb-2"><%=Server.HTMLEncode(rs("sso") & "")%></p>
<%
If appLink <> "" Then
Response.Write("<p class='mb-2'><a href='" & Server.HTMLEncode(appLink) & "' target='_blank' title='Launch Application'><i class='zmdi zmdi-link' style='font-size:1.2rem; color:#007bff;'></i> <span style='color:#007bff;'>Launch Application</span></a></p>")
End If
If installPath <> "" Then
Response.Write("<p class='mb-2'><a href='" & Server.HTMLEncode(installPath) & "' target='_blank' title='Download Installation Files'><i class='zmdi zmdi-download' style='font-size:1.2rem; color:#28a745;'></i> <span style='color:#28a745;'>Download Installation Files</span></a></p>")
End If
If docPath <> "" Then
Response.Write("<p class='mb-2'><a href='" & Server.HTMLEncode(docPath) & "' target='_blank' title='View Documentation'><i class='zmdi zmdi-file-text' style='font-size:1.2rem; color:#17a2b8;'></i> <span style='color:#17a2b8;'>View Documentation</span></a></p>")
End If
%>
</div>
<div class="col-md-12">
<h5 class="mt-2 mb-3">Application Notes</h5>
<div class="table-responsive">
<table class="table table-hover table-striped">
<tbody>
<tr>
<td>
<strong><%Response.Write(rs("appname"))%></strong>:
</td>
</tr>
<tr>
<td><%Response.Write(rs("applicationnotes"))%>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-12">
<h5 class="mt-4 mb-3"><i class="zmdi zmdi-collection-bookmark"></i> Related Knowledge Base Articles</h5>
<%
' Query knowledge base articles for this application
' Use keyword matching similar to search.asp - match on app name in keywords/description
Dim rsKB, sqlKB, appName
appName = rs("appname") & ""
' Search for articles where keywords or shortdescription contain the app name
' Also include articles explicitly linked via appid
' Sort by clicks (highest first), then prioritize directly linked articles
sqlKB = "SELECT linkid, linkurl, shortdescription, COALESCE(clicks, 0) as clicks, " & _
"CASE WHEN appid = " & appid & " THEN 1 ELSE 0 END as direct_link, " & _
"CAST(COALESCE(clicks, 0) AS SIGNED) as clicks_num " & _
"FROM knowledgebase " & _
"WHERE isactive = 1 " & _
"AND (appid = " & appid & " " & _
" OR keywords LIKE '%" & Replace(appName, "'", "''") & "%' " & _
" OR shortdescription LIKE '%" & Replace(appName, "'", "''") & "%') " & _
"ORDER BY clicks_num DESC, direct_link DESC"
Set rsKB = objConn.Execute(sqlKB)
If Not rsKB.EOF Then
%>
<div class="table-responsive">
<table class="table table-hover" style="font-size: 1rem;">
<thead>
<tr>
<th style="padding: 12px;">Article</th>
<th style="width:100px; text-align:center; padding: 12px;">
<i class="zmdi zmdi-eye"></i> Clicks
</th>
</tr>
</thead>
<tbody>
<%
' Declare loop variables once outside the loop
Dim kbClicks, kbDesc, kbClicksNum
While Not rsKB.EOF
' Get click count with proper error handling
On Error Resume Next
kbClicks = rsKB("clicks")
If Err.Number <> 0 Or IsNull(kbClicks) Or kbClicks = "" Then
kbClicks = 0
End If
' Convert to number for comparison
kbClicksNum = CLng(kbClicks)
If Err.Number <> 0 Then
kbClicksNum = 0
kbClicks = 0
End If
' Get description
kbDesc = rsKB("shortdescription")
If Err.Number <> 0 Or IsNull(kbDesc) Then
kbDesc = "[No description]"
End If
On Error Goto 0
%>
<tr>
<td style="padding: 12px;">
<a href="./clickcounter.asp?linkid=<%=Server.HTMLEncode(rsKB("linkid"))%>"
target="_blank"
title="<%=Server.HTMLEncode(kbDesc)%>"
style="font-size: 1rem;">
<i class="zmdi zmdi-link" style="font-size: 1.1rem;"></i> <%=Server.HTMLEncode(kbDesc)%>
</a>
</td>
<td style="text-align:center; padding: 12px;">
<%
' Display click count with badge styling (improved contrast for readability)
If kbClicksNum = 0 Then
Response.Write("<span class=""badge badge-secondary"" style=""font-size: 0.9rem; padding: 6px 10px; background-color: #6c757d; color: #fff;"">" & kbClicks & "</span>")
ElseIf kbClicksNum < 10 Then
Response.Write("<span class=""badge badge-info"" style=""font-size: 0.9rem; padding: 6px 10px; background-color: #17a2b8; color: #fff;"">" & kbClicks & "</span>")
ElseIf kbClicksNum < 50 Then
Response.Write("<span class=""badge badge-warning"" style=""font-size: 0.9rem; padding: 6px 10px; background-color: #ffc107; color: #212529;"">" & kbClicks & "</span>")
Else
Response.Write("<span class=""badge badge-success"" style=""font-size: 0.9rem; padding: 6px 10px; background-color: #28a745; color: #fff;"">" & kbClicks & "</span>")
End If
%>
</td>
</tr>
<%
rsKB.MoveNext
Wend
%>
</tbody>
</table>
</div>
<%
Else
' No knowledge base articles found
Response.Write("<p class='text-muted' style='padding:20px; text-align:center;'>")
Response.Write("<i class='zmdi zmdi-info-outline' style='font-size:48px; opacity:0.3; display:block; margin-bottom:10px;'></i>")
Response.Write("No knowledge base articles found for this application.")
Response.Write("</p>")
End If
rsKB.Close
Set rsKB = Nothing
%>
</div>
</div>
<!--/row-->
</div>
<div class="tab-pane" id="edit">
<h5 class="mb-3">Edit Application</h5>
<form method="post" action="./editapplicationdirect.asp">
<input type="hidden" name="appid" value="<%=Server.HTMLEncode(rs("appid"))%>">
<div class="form-group">
<label for="appname">Application Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="appname" name="appname"
value="<%=Server.HTMLEncode(rs("appname") & "")%>"
required maxlength="50">
</div>
<div class="form-group">
<label for="appdescription">Description</label>
<input type="text" class="form-control" id="appdescription" name="appdescription"
value="<%=Server.HTMLEncode(rs("appdescription") & "")%>"
maxlength="255">
</div>
<div class="form-group">
<label for="supportteamid">Support Team <span class="text-danger">*</span></label>
<div class="input-group">
<select class="form-control" id="supportteamid" name="supportteamid" required>
<option value='<%response.write(rs("supportteamid"))%>'><%Response.Write(rs("teamname"))%></option>
<%
' Get all support teams for dropdown (same pattern as displayprinter.asp)
Dim rsSupportTeams, sqlSupportTeams
sqlSupportTeams = "SELECT supporteamid, teamname FROM supportteams WHERE isactive=1 ORDER BY teamname ASC"
Set rsSupportTeams = objconn.Execute(sqlSupportTeams)
While Not rsSupportTeams.EOF
If CLng(rsSupportTeams("supporteamid")) <> CLng(rs("supportteamid")) Then
Response.Write("<option value='" & rsSupportTeams("supporteamid") & "'>" & Server.HTMLEncode(rsSupportTeams("teamname")) & "</option>")
End If
rsSupportTeams.MoveNext
Wend
rsSupportTeams.Close
Set rsSupportTeams = Nothing
%>
<option value="new">+ Add New Support Team</option>
</select>
<div class="input-group-append">
<button type="button" class="btn btn-info" id="addSupportTeamBtn">
<i class="zmdi zmdi-plus"></i> New
</button>
</div>
</div>
</div>
<!-- Hidden section for adding new support team -->
<div id="newSupportTeamSection" class="new-support-team-section" style="display:none; padding:15px; background:rgba(255,255,255,0.03); border:1px solid rgba(255,255,255,0.1); border-radius:5px; margin-bottom:15px;">
<h6 class="mb-3"><i class="zmdi zmdi-plus-circle"></i> New Support Team</h6>
<div class="form-group">
<label for="newsupportteamname">Team Name</label>
<input type="text" class="form-control" id="newsupportteamname" name="newsupportteamname"
maxlength="50" placeholder="e.g., IT Support, Engineering">
</div>
<div class="form-group">
<label for="newsupportteamurl">Team URL</label>
<input type="text" class="form-control" id="newsupportteamurl" name="newsupportteamurl"
maxlength="512" placeholder="e.g., Service Now URL or team page">
<small class="form-text text-muted">
Optional - Link to Service Now page or team website
</small>
</div>
<div class="form-group">
<label for="newappownerid">App Owner</label>
<div class="input-group">
<select class="form-control" id="newappownerid" name="newappownerid">
<option value="">-- Select App Owner --</option>
<%
Dim rsAppOwners, sqlAppOwners
sqlAppOwners = "SELECT appownerid, appowner FROM appowners WHERE isactive=1 ORDER BY appowner ASC"
Set rsAppOwners = objconn.Execute(sqlAppOwners)
While Not rsAppOwners.EOF
Response.Write("<option value='" & rsAppOwners("appownerid") & "'>" & Server.HTMLEncode(rsAppOwners("appowner")) & "</option>")
rsAppOwners.MoveNext
Wend
rsAppOwners.Close
Set rsAppOwners = Nothing
%>
<option value="new">+ Add New App Owner</option>
</select>
<div class="input-group-append">
<button type="button" class="btn btn-info btn-sm" id="addAppOwnerBtn">
<i class="zmdi zmdi-plus"></i> New
</button>
</div>
</div>
</div>
<!-- Hidden section for adding new app owner -->
<div id="newAppOwnerSection" style="display:none; padding:10px; background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.15); border-radius:3px; margin-bottom:10px;">
<h6 class="mb-2" style="font-size:0.9rem;"><i class="zmdi zmdi-account"></i> New App Owner</h6>
<div class="form-group mb-2">
<label for="newappownername" style="font-size:0.85rem;">Name</label>
<input type="text" class="form-control form-control-sm" id="newappownername" name="newappownername"
maxlength="50" placeholder="e.g., John Smith">
</div>
<div class="form-group mb-2">
<label for="newappownersso" style="font-size:0.85rem;">SSO</label>
<input type="text" class="form-control form-control-sm" id="newappownersso" name="newappownersso"
maxlength="50" placeholder="e.g., jsmith">
</div>
<button type="button" class="btn btn-sm btn-secondary btn-sm" id="cancelNewAppOwner">
<i class="zmdi zmdi-close"></i> Cancel
</button>
</div>
<button type="button" class="btn btn-sm btn-secondary" id="cancelNewSupportTeam">
<i class="zmdi zmdi-close"></i> Cancel
</button>
</div>
<div class="form-group">
<label for="applicationnotes">Application Notes</label>
<textarea class="form-control" id="applicationnotes" name="applicationnotes"
rows="4" maxlength="512"><%=Server.HTMLEncode(rs("applicationnotes") & "")%></textarea>
</div>
<div class="form-group">
<label for="applicationlink">Application Link</label>
<input type="text" class="form-control" id="applicationlink" name="applicationlink"
value="<%=Server.HTMLEncode(rs("applicationlink") & "")%>"
maxlength="512"
placeholder="https://app.example.com or application://...">
<small class="form-text text-muted">
Direct URL to launch or access the application
</small>
</div>
<div class="form-group">
<label for="installpath">Installation Path/URL</label>
<input type="text" class="form-control" id="installpath" name="installpath"
value="<%=Server.HTMLEncode(rs("installpath") & "")%>"
maxlength="255"
placeholder="\\server\share\installer.exe or http://...">
</div>
<div class="form-group">
<label for="documentationpath">Documentation Path/URL</label>
<input type="text" class="form-control" id="documentationpath" name="documentationpath"
value="<%=Server.HTMLEncode(rs("documentationpath") & "")%>"
maxlength="512"
placeholder="\\server\docs or http://...">
</div>
<div class="form-group">
<label for="image">Image Filename</label>
<input type="text" class="form-control" id="image" name="image"
value="<%=Server.HTMLEncode(rs("image") & "")%>"
maxlength="255"
placeholder="app-logo.png">
<small class="form-text text-muted">
Place image in <code>./images/applications/</code> folder
</small>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
id="isinstallable" name="isinstallable" value="1"
<%If rs("isinstallable") Then Response.Write("checked")%>>
<label class="custom-control-label" for="isinstallable">
Is Installable
</label>
</div>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
id="isprinter" name="isprinter" value="1"
<%If rs("isprinter") Then Response.Write("checked")%>>
<label class="custom-control-label" for="isprinter">
Printer Application
</label>
</div>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
id="islicenced" name="islicenced" value="1"
<%If rs("islicenced") Then Response.Write("checked")%>>
<label class="custom-control-label" for="islicenced">
Requires License
</label>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
id="isactive" name="isactive" value="1"
<%If rs("isactive") Then Response.Write("checked")%>>
<label class="custom-control-label" for="isactive">
Active
</label>
</div>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input"
id="ishidden" name="ishidden" value="1"
<%If rs("ishidden") Then Response.Write("checked")%>>
<label class="custom-control-label" for="ishidden">
Hidden
</label>
</div>
</div>
</div>
</div>
<div class="form-group text-right">
<button type="submit" class="btn btn-primary">
<i class="icon-check"></i> Save Changes
</button>
<a href="./displayapplications.asp" class="btn btn-secondary">
<i class="icon-close"></i> Cancel
</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- End Row -->
<!-- End container-fluid-->
</div><!--End content-wrapper-->
<!--Start Back To Top Button-->
<a href="javaScript:void();" class="back-to-top"><i class="fa fa-angle-double-up"></i> </a>
<!--End Back To Top Button-->
<!--Start footer-->
<footer class="footer">
<div class="container">
<div class="text-center">
</div>
</div>
</footer>
<!--End footer-->
</div>
<!--End wrapper-->
<!-- Bootstrap core JavaScript-->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/popper.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<!-- simplebar js -->
<script src="assets/plugins/simplebar/js/simplebar.js"></script>
<!-- sidebar-menu js -->
<script src="assets/js/sidebar-menu.js"></script>
<!-- Custom scripts -->
<script src="assets/js/app-script.js"></script>
<script>
$(document).ready(function() {
// Show/hide new support team section
$('#addSupportTeamBtn, #supportteamid').on('change click', function() {
if ($('#supportteamid').val() === 'new' || $(this).attr('id') === 'addSupportTeamBtn') {
$('#supportteamid').val('new');
$('#newSupportTeamSection').slideDown();
$('#newsupportteamname').prop('required', true);
$('#newappownerid').prop('required', true);
}
});
$('#cancelNewSupportTeam').on('click', function() {
$('#newSupportTeamSection').slideUp();
$('#supportteamid').val($('#supportteamid option:first').val());
$('#newsupportteamname').val('').prop('required', false);
$('#newsupportteamurl').val('');
$('#newappownerid').val('').prop('required', false);
// Also hide and clear app owner section
$('#newAppOwnerSection').hide();
$('#newappownername').val('').prop('required', false);
$('#newappownersso').val('').prop('required', false);
});
// Show/hide new app owner section (nested within support team)
$('#addAppOwnerBtn, #newappownerid').on('change click', function() {
if ($('#newappownerid').val() === 'new' || $(this).attr('id') === 'addAppOwnerBtn') {
$('#newappownerid').val('new');
$('#newAppOwnerSection').slideDown();
$('#newappownername').prop('required', true);
$('#newappownersso').prop('required', true);
}
});
$('#cancelNewAppOwner').on('click', function() {
$('#newAppOwnerSection').slideUp();
$('#newappownerid').val('');
$('#newappownername').val('').prop('required', false);
$('#newappownersso').val('').prop('required', false);
});
// Form validation
$('form').on('submit', function(e) {
// If adding new support team, make sure fields are filled
if ($('#supportteamid').val() === 'new') {
if ($('#newsupportteamname').val().trim() === '') {
e.preventDefault();
alert('Please enter a support team name or select an existing one');
$('#newsupportteamname').focus();
return false;
}
// Check if adding new app owner within new support team
if ($('#newappownerid').val() === 'new') {
if ($('#newappownername').val().trim() === '') {
e.preventDefault();
alert('Please enter an app owner name or select an existing one');
$('#newappownername').focus();
return false;
}
if ($('#newappownersso').val().trim() === '') {
e.preventDefault();
alert('Please enter an SSO for the new app owner');
$('#newappownersso').focus();
return false;
}
} else if ($('#newappownerid').val() === '') {
e.preventDefault();
alert('Please select an app owner for the new support team');
$('#newappownerid').focus();
return false;
}
}
});
});
</script>
</body>
</html>
<%
rs.Close
Set rs = Nothing
objConn.Close
%>