Skip to content

Commit 38c06ee

Browse files
committed
initial commit
0 parents  commit 38c06ee

File tree

15 files changed

+1541
-0
lines changed

15 files changed

+1541
-0
lines changed

LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2025, Automatic Controls Equipment Systems, Inc.
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
3. Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# CLI Web Terminal
2+
3+
WebCTRL is a trademark of Automated Logic Corporation. Any other trademarks mentioned herein are the property of their respective owners.
4+
5+
This WebCTRL add-on permits operators with administrative privileges access to a web interface for the server's shell. If the WebCTRL server is running on Linux, then *Bash* is shown. If the WebCTRL server is running on Windows, then *Command Prompt* is shown. Note that you can access *PowerShell* from within *Command Prompt* as well.
6+
7+
## Usage
8+
9+
If your server requires signed add-ons, copy the authenticating certificate [*ACES.cer*](https://github.com/automatic-controls/addon-dev-script/blob/main/ACES.cer?raw=true) to the *./programdata/addons* directory of your *WebCTRL* installation folder. Install [*CLI_Web_Terminal.addon*](https://github.com/automatic-controls/cli-addon/releases/latest/download/CLI_Web_Terminal.addon) using the *WebCTRL* interface. Navigate to this add-on's main page (e.g, *localhost/CLI_Web_Terminal*) to access the server's shell. You may also click the **Web Terminal** option listed in the system menu in the top-right corner of WebCTRL. After installing the add-on, you must logout and login to see the system menu option.

config/BUILD_DETAILS

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
JDK Version:
2+
openjdk 22.0.1 2024-04-16
3+
OpenJDK Runtime Environment (build 22.0.1+8-16)
4+
OpenJDK 64-Bit Server VM (build 22.0.1+8-16, mixed mode, sharing)
5+
6+
Compilation Flags:
7+
--release 11
8+
9+
Runtime Dependencies:
10+
addonsupport-api-addon-1.10.0
11+
alarmmanager-api-addon-1.10.0
12+
bacnet-api-core-1.10.007-20240227.1003r
13+
directaccess-api-addon-1.10.0
14+
tomcat-embed-core-9.0.87
15+
webaccess-api-addon-1.10.0
16+
xdatabase-api-addon-1.10.0
17+
18+
Packaged Dependencies:

config/COMPILE_FLAGS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--release 11

root/info.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<extension version="1">
2+
<name>CLI_Web_Terminal</name>
3+
<description>Web interface to access the local shell environment of the WebCTRL server.</description>
4+
<version>0.1.1</version>
5+
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
6+
<system-menu-provider>aces.webctrl.cli.web.SystemMenuEditor</system-menu-provider>
7+
</extension>

root/webapp/WEB-INF/web.xml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<web-app>
4+
5+
<listener>
6+
<listener-class>aces.webctrl.cli.core.Initializer</listener-class>
7+
</listener>
8+
9+
<welcome-file-list>
10+
<welcome-file>index</welcome-file>
11+
</welcome-file-list>
12+
13+
<servlet>
14+
<servlet-name>MainPage</servlet-name>
15+
<servlet-class>aces.webctrl.cli.web.MainPage</servlet-class>
16+
</servlet>
17+
<servlet-mapping>
18+
<servlet-name>MainPage</servlet-name>
19+
<url-pattern>/index</url-pattern>
20+
</servlet-mapping>
21+
22+
<security-constraint>
23+
<web-resource-collection>
24+
<web-resource-name>WEB</web-resource-name>
25+
<url-pattern>/*</url-pattern>
26+
</web-resource-collection>
27+
</security-constraint>
28+
29+
</web-app>

root/webapp/main.css

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
body, input, textarea, select {
2+
background-color:black;
3+
color:white;
4+
}
5+
.e {
6+
margin-left:0.5em;
7+
margin-right:0.5em;
8+
margin-top:0.25em;
9+
margin-bottom:0.25em;
10+
}
11+
.c {
12+
text-align:center;
13+
}
14+
.column {
15+
float:left;
16+
width:50%;
17+
}
18+
.row {
19+
content: "";
20+
display:table;
21+
clear:both;
22+
width:100%;
23+
}
24+
button {
25+
border:1px solid white;
26+
border-radius: 8px;
27+
padding-left:7px;
28+
padding-right:7px;
29+
padding-top:2px;
30+
padding-bottom:2px;
31+
text-decoration: none;
32+
color:lightgreen;
33+
background-color: transparent;
34+
cursor:pointer;
35+
user-select: none;
36+
}
37+
button:hover {
38+
color:darkgoldenrod;
39+
}
40+
button:active {
41+
color:teal;
42+
}
43+
button:disabled {
44+
background-color:darkslategray;
45+
color:forestgreen;
46+
cursor:default;
47+
}
48+
a {
49+
border:1px solid white;
50+
border-radius: 8px;
51+
padding-left:6px;
52+
padding-right:6px;
53+
padding-top:1px;
54+
padding-bottom:1px;
55+
text-decoration: none;
56+
background-color: transparent;
57+
user-select: none;
58+
}
59+
a:link,a:visited {
60+
color: lightgreen;
61+
}
62+
a.nav:link,a.nav:visited {
63+
color: violet;
64+
}
65+
a:hover,a.nav:hover {
66+
color:darkgoldenrod;
67+
}
68+
a:active,a.nav:active {
69+
color:teal;
70+
}
71+
td, th {
72+
padding:4px;
73+
border:solid 1px gray;
74+
}
75+
tr:nth-child(odd) {
76+
background-color:#222222;
77+
}
78+
tr:nth-child(even) {
79+
background-color:#090909;
80+
}
81+
th {
82+
background-color:darkslategray;
83+
}
84+
table {
85+
border-collapse:collapse;
86+
margin:0 auto;
87+
}
88+
thead,tbody,tfoot {
89+
border:solid 3px gray;
90+
}
91+
.divGrouping {
92+
display:inline-block;
93+
margin-left:1vw;
94+
margin-right:1vw;
95+
margin-top:5px;
96+
margin-bottom:5px;
97+
}
98+
.stickyBar {
99+
position:sticky;
100+
top:0;
101+
width:100%;
102+
background-color:black;
103+
padding-top:0.75em;
104+
border-bottom:1px solid gray;
105+
border-top:1px solid gray;
106+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package aces.webctrl.cli.core;
2+
import com.controlj.green.addonsupport.*;
3+
import java.nio.file.*;
4+
import java.security.SecureRandom;
5+
import javax.servlet.*;
6+
import java.util.*;
7+
public class Initializer implements ServletContextListener {
8+
public final static SecureRandom RANDOM = new SecureRandom();
9+
/** Whether the operating system is Linux based */
10+
public final static boolean LINUX = System.getProperty("os.name").toLowerCase().contains("linux");
11+
/** Contains basic information about this addon */
12+
public volatile static AddOnInfo info = null;
13+
/** The name of this addon */
14+
private volatile static String name;
15+
/** Prefix used for constructing relative URL paths */
16+
private volatile static String prefix;
17+
/** Path to the private directory for this addon */
18+
private volatile static Path root;
19+
/** Path to WebCTRL's active system directory */
20+
public volatile static Path systemDir = null;
21+
/** Logger for this addon */
22+
private volatile static FileLogger logger;
23+
/** Becomes true when the servlet context is destroyed */
24+
public volatile static boolean stop = false;
25+
/** Stores references to Process threads */
26+
private final static HashMap<Long,ShellProcess> processes = new HashMap<>();
27+
/**
28+
* Entry point of this add-on.
29+
*/
30+
@Override public void contextInitialized(ServletContextEvent sce){
31+
info = AddOnInfo.getAddOnInfo();
32+
name = info.getName();
33+
prefix = '/'+name+'/';
34+
root = info.getPrivateDir().toPath();
35+
logger = info.getDateStampLogger();
36+
systemDir = root.getParent().getParent().getParent();
37+
}
38+
/**
39+
* Kills the primary processing thread and releases all resources.
40+
*/
41+
@Override public void contextDestroyed(ServletContextEvent sce){
42+
stop = true;
43+
boolean any = false;
44+
synchronized (processes){
45+
for (ShellProcess p : processes.values()){
46+
if (!p.isKilled()){
47+
p.getThread().interrupt();
48+
any|=true;
49+
}
50+
}
51+
}
52+
if (any){
53+
boolean cont = true;
54+
while (cont){
55+
try{ Thread.sleep(300L); }catch(Throwable t){}
56+
cont = false;
57+
for (ShellProcess p : processes.values()){
58+
if (!p.isKilled()){
59+
cont = true;
60+
break;
61+
}
62+
}
63+
}
64+
}
65+
try{ Thread.sleep(50L); }catch(Throwable t){}
66+
}
67+
public static void addProcess(ShellProcess t){
68+
if (stop){
69+
return;
70+
}
71+
synchronized (processes){
72+
if (stop){
73+
return;
74+
}
75+
ShellProcess p;
76+
Iterator<ShellProcess> i = processes.values().iterator();
77+
while (i.hasNext()){
78+
p = i.next();
79+
if (p.isKilled()){
80+
i.remove();
81+
}
82+
}
83+
processes.put(t.ID,t);
84+
}
85+
}
86+
public static ShellProcess getProcess(long id, String key){
87+
ShellProcess p;
88+
synchronized (processes){
89+
p = processes.get(id);
90+
}
91+
if (p==null || !p.KEY.equals(key)){
92+
return null;
93+
}
94+
return p;
95+
}
96+
/**
97+
* @return the name of this application.
98+
*/
99+
public static String getName(){
100+
return name;
101+
}
102+
/**
103+
* @return the prefix used for constructing relative URL paths.
104+
*/
105+
public static String getPrefix(){
106+
return prefix;
107+
}
108+
/**
109+
* Logs a message.
110+
*/
111+
public synchronized static void log(String str){
112+
logger.println(str);
113+
}
114+
/**
115+
* Logs an error.
116+
*/
117+
public synchronized static void log(Throwable t){
118+
logger.println(t);
119+
}
120+
}

0 commit comments

Comments
 (0)