1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 11:24:35 +00:00

Compare commits

..

5 Commits

Author SHA1 Message Date
Yury Shkoda
66232aefd2 chore(lint): bumped prettier and fixed lint issues 2023-09-21 17:58:47 +03:00
Yury Shkoda
bf35791655 chore(lint): fixed Session.ts 2023-09-21 17:52:28 +03:00
Yury Shkoda
2dc11630e4 chore(api): regenerated swagger.yaml 2023-09-21 17:45:52 +03:00
Yury Shkoda
1473925896 fix(jsonwebtoken): bumped version to avoid vulnerability 2023-09-21 17:45:21 +03:00
Yury Shkoda
b472f1bd61 chore(scripts): used cpr package to improve coping 2023-09-21 17:44:31 +03:00
19 changed files with 2901 additions and 2470 deletions

View File

@@ -1,38 +1,3 @@
# [0.38.0](https://github.com/sasjs/server/compare/v0.37.0...v0.38.0) (2024-10-30)
### Features
* **api:** enabled query params in stp/trigger endpoint ([5cda9cd](https://github.com/sasjs/server/commit/5cda9cd5d8623b7ea2ecd989d7808f47ec866672))
# [0.37.0](https://github.com/sasjs/server/compare/v0.36.0...v0.37.0) (2024-10-29)
### Features
* **stp:** added trigger endpoint ([b0723f1](https://github.com/sasjs/server/commit/b0723f14448d60ffce4f2175cf8a73fc4d4dd0ee))
# [0.36.0](https://github.com/sasjs/server/compare/v0.35.4...v0.36.0) (2024-10-29)
### Features
* **code:** added code/trigger API endpoint ([ffcf193](https://github.com/sasjs/server/commit/ffcf193b87d811b166d79af74013776a253b50b0))
## [0.35.4](https://github.com/sasjs/server/compare/v0.35.3...v0.35.4) (2024-01-15)
### Bug Fixes
* **api:** fixed env issue in MacOS executable ([73d965d](https://github.com/sasjs/server/commit/73d965daf54b16c0921e4b18d11a1e6f8650884d))
## [0.35.3](https://github.com/sasjs/server/compare/v0.35.2...v0.35.3) (2023-11-07)
### Bug Fixes
* enable embedded LFs in JS STP vars ([7e8cbbf](https://github.com/sasjs/server/commit/7e8cbbf377b27a7f5dd9af0bc6605c01f302f5d9))
## [0.35.2](https://github.com/sasjs/server/compare/v0.35.1...v0.35.2) (2023-08-07)

View File

@@ -1,206 +1,84 @@
<mxfile host="65bd71144e">
<diagram id="HJy_QFGaI9JSrArARLup" name="Page-1">
<mxGraphModel dx="3103" dy="2723" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<mxGraphModel dx="1908" dy="2140" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="7" value="SASjs Server" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;fontSize=30;" parent="1" vertex="1">
<mxGeometry x="30" y="-150" width="360" height="1250" as="geometry"/>
<mxCell id="4" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" vertex="1" parent="1">
<mxGeometry x="-360" y="-120" width="40" height="80" as="geometry"/>
</mxCell>
<mxCell id="36" value="&lt;font style=&quot;font-size: 22px&quot;&gt;Internal Authentication&lt;/font&gt;" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
<mxGeometry x="50" y="-60" width="320" height="330" as="geometry"/>
<mxCell id="7" value="SASjs Server" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;fontSize=30;" vertex="1" parent="1">
<mxGeometry x="30" y="-150" width="360" height="850" as="geometry"/>
</mxCell>
<mxCell id="4" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" parent="1" vertex="1">
<mxGeometry x="-740" y="-120" width="40" height="80" as="geometry"/>
</mxCell>
<mxCell id="8" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" parent="1" target="28" edge="1">
<mxCell id="8" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="28">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-530" y="23" as="sourcePoint"/>
<mxPoint x="-340" y="23" as="sourcePoint"/>
<mxPoint x="115" y="22.586363636363558" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="11" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/authorize&lt;br&gt;(username,password,clientId)&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="8" vertex="1" connectable="0">
<mxCell id="11" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/authorize&lt;br&gt;(username,password,clientId)&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="8">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="14" value="" style="edgeStyle=none;html=1;exitX=-0.002;exitY=0.874;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="28" edge="1">
<mxCell id="14" value="" style="edgeStyle=none;html=1;exitX=-0.002;exitY=0.874;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="28">
<mxGeometry relative="1" as="geometry">
<mxPoint x="110" y="80" as="sourcePoint"/>
<mxPoint x="-530" y="80" as="targetPoint"/>
<mxPoint x="-340" y="80" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="16" value="&lt;font color=&quot;#a31515&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;span style=&quot;font-size: 12px&quot;&gt;`code`&lt;/span&gt;&lt;/font&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="14" vertex="1" connectable="0">
<mxCell id="16" value="&lt;font color=&quot;#a31515&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;span style=&quot;font-size: 12px&quot;&gt;`code`&lt;/span&gt;&lt;/font&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="14">
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="21" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" parent="1" vertex="1">
<mxGeometry x="-730" y="1100" width="40" height="80" as="geometry"/>
<mxCell id="21" value="End user" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;fontStyle=0" vertex="1" parent="1">
<mxGeometry x="-360" y="545" width="40" height="80" as="geometry"/>
</mxCell>
<mxCell id="22" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" parent="1" target="30" edge="1">
<mxCell id="22" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="30">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-530" y="163" as="sourcePoint"/>
<mxPoint x="-340" y="165" as="sourcePoint"/>
<mxPoint x="115" y="165" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="23" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/token&lt;/span&gt;&lt;/div&gt;&lt;span style=&quot;color: #a31515&quot;&gt;(clientId,code)&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="22" vertex="1" connectable="0">
<mxCell id="23" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/token&lt;/span&gt;&lt;/div&gt;&lt;span style=&quot;color: #a31515&quot;&gt;(clientId,code)&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="22">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="24" value="" style="edgeStyle=none;html=1;exitX=0.009;exitY=0.905;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="30" edge="1">
<mxCell id="24" value="" style="edgeStyle=none;html=1;exitX=0.009;exitY=0.905;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="30">
<mxGeometry relative="1" as="geometry">
<mxPoint x="210" y="222.5" as="sourcePoint"/>
<mxPoint x="-530" y="223" as="targetPoint"/>
<mxPoint x="-340" y="223" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="25" value="&lt;font color=&quot;#a31515&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;span style=&quot;font-size: 12px&quot;&gt;`&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;accessToken&lt;/span&gt;&lt;span style=&quot;font-size: 12px ; color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace&quot;&gt;` &amp;amp; `&lt;/span&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;refreshToken&lt;/span&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;`&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="24" vertex="1" connectable="0">
<mxCell id="25" value="&lt;font color=&quot;#a31515&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;span style=&quot;font-size: 12px&quot;&gt;`&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;accessToken&lt;/span&gt;&lt;span style=&quot;font-size: 12px ; color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace&quot;&gt;` &amp;amp; `&lt;/span&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;refreshToken&lt;/span&gt;&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;`&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="24">
<mxGeometry x="0.1931" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="26" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;" parent="1" source="21" target="4" edge="1">
<mxCell id="26" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;" edge="1" parent="1" source="21" target="4">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="-340" y="240" as="sourcePoint"/>
<mxPoint x="-290" y="190" as="targetPoint"/>
<mxPoint x="40" y="240" as="sourcePoint"/>
<mxPoint x="90" y="190" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="28" value="&lt;span&gt;Validates&lt;/span&gt;&lt;br&gt;&lt;span&gt;username/password/clientId&lt;/span&gt;&lt;br&gt;&lt;span&gt;and issue short&lt;/span&gt;&lt;br&gt;&lt;span&gt;Authorization code&lt;/span&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxCell id="28" value="&lt;span&gt;Validates&lt;/span&gt;&lt;br&gt;&lt;span&gt;username/password/clientId&lt;/span&gt;&lt;br&gt;&lt;span&gt;and issue short&lt;/span&gt;&lt;br&gt;&lt;span&gt;Authorization code&lt;/span&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="115" width="190" height="90" as="geometry"/>
</mxCell>
<mxCell id="30" value="Validates&lt;br&gt;clientId &amp;amp; authorization code&lt;br&gt;and issue&lt;br&gt;Access Token &amp;amp; Refresh Token" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxCell id="30" value="Validates&lt;br&gt;clientId &amp;amp; authorization code&lt;br&gt;and issue&lt;br&gt;Access Token &amp;amp; Refresh Token" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="115" y="140" width="190" height="90" as="geometry"/>
</mxCell>
<mxCell id="32" value="Protected APIs&lt;br&gt;Authenticate requests &lt;br&gt;with provided Bearer Token" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" parent="1" vertex="1">
<mxGeometry x="50" y="920" width="320" height="150" as="geometry"/>
<mxCell id="32" value="Protected APIs&lt;br&gt;Authenticate requests &lt;br&gt;with provided Bearer Token" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
<mxGeometry x="50" y="280" width="320" height="400" as="geometry"/>
</mxCell>
<mxCell id="33" value="" style="edgeStyle=none;html=1;entryX=-0.012;entryY=0.384;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="32" edge="1">
<mxCell id="33" value="" style="edgeStyle=none;html=1;entryX=0;entryY=0.373;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="32">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-520" y="978" as="sourcePoint"/>
<mxPoint x="-80" y="819" as="targetPoint"/>
<mxPoint x="-340" y="432.5" as="sourcePoint"/>
<mxPoint x="-10" y="430" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="34" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;font color=&quot;#a31515&quot;&gt;Request with Access Token&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="33" vertex="1" connectable="0">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="37" value="Browser" style="rounded=0;whiteSpace=wrap;html=1;fontSize=22;" vertex="1" parent="1">
<mxGeometry x="-590" y="-100" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="38" value="Browser" style="rounded=0;whiteSpace=wrap;html=1;fontSize=22;" vertex="1" parent="1">
<mxGeometry x="-590" y="1110" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="39" value="" style="endArrow=none;dashed=1;html=1;fontSize=22;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" edge="1" parent="1" source="38" target="37">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="-340" y="390" as="sourcePoint"/>
<mxPoint x="-290" y="340" as="targetPoint"/>
<Array as="points"/>
</mxGeometry>
</mxCell>
<mxCell id="40" value="&lt;font style=&quot;font-size: 22px&quot;&gt;Okta Authentication&lt;/font&gt;" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
<mxGeometry x="50" y="300" width="320" height="560" as="geometry"/>
</mxCell>
<mxCell id="41" value="" style="edgeStyle=none;html=1;entryX=-0.013;entryY=0.092;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="49">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-530" y="373" as="sourcePoint"/>
<mxPoint x="115" y="372.58636363636356" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="42" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #a31515&quot;&gt;/SASjsApi/auth/okta/authorize&lt;br&gt;&lt;/span&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="41">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="49" value="redirects to okta server&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;OKTA OIDC middleware&lt;br&gt;https://github.com/okta/okta-oidc-middleware&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;OKTA nodeJS Express implementation&lt;br&gt;https://github.com/okta/samples-nodejs-express-4/tree/master/okta-hosted-login&lt;br&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="115" y="350" width="190" height="280" as="geometry"/>
</mxCell>
<mxCell id="75" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=14;" edge="1" parent="1" source="50" target="32">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="50" value="Validates express session &lt;br&gt;through OKTA OIDC middleware" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="115" y="710" width="190" height="90" as="geometry"/>
</mxCell>
<mxCell id="51" value="&lt;span style=&quot;font-size: 22px&quot;&gt;Okta Authorization Server&lt;br&gt;&lt;/span&gt;" style="whiteSpace=wrap;html=1;verticalAlign=top;fontStyle=0;" vertex="1" parent="1">
<mxGeometry x="600" y="300" width="320" height="380" as="geometry"/>
</mxCell>
<mxCell id="52" value="" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="665" y="350" width="190" height="280" as="geometry"/>
</mxCell>
<mxCell id="53" value="" style="endArrow=classic;html=1;fontSize=22;exitX=1.002;exitY=0.123;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="49">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="400" y="480" as="sourcePoint"/>
<mxPoint x="660" y="384" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="54" value="&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;/authorize&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=22;" vertex="1" connectable="0" parent="53">
<mxGeometry x="0.0222" y="1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="58" value="" style="endArrow=classic;html=1;fontSize=22;exitX=-0.016;exitY=0.291;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="52">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-300" y="470" as="sourcePoint"/>
<mxPoint x="-530" y="431" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="61" value="302 redirect to authentication prompt&amp;nbsp;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=22;" vertex="1" connectable="0" parent="58">
<mxGeometry x="-0.659" y="3" relative="1" as="geometry">
<mxPoint x="-630" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="62" value="" style="endArrow=classic;html=1;fontSize=22;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-530" y="500" as="sourcePoint"/>
<mxPoint x="665" y="500.48" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="64" value="Authentication &amp;amp; Consent" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=22;" vertex="1" connectable="0" parent="62">
<mxGeometry x="-0.4695" y="6" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="65" value="" style="endArrow=classic;html=1;fontSize=22;exitX=0;exitY=0.679;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.995;entryY=0.679;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="52" target="49">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="230" y="560" as="sourcePoint"/>
<mxPoint x="280" y="510" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="66" value="Authorization Code to redirect uri" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" vertex="1" connectable="0" parent="65">
<mxGeometry x="0.0583" y="1" relative="1" as="geometry">
<mxPoint x="26" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="67" value="" style="endArrow=classic;html=1;fontSize=22;exitX=0;exitY=0.679;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.995;entryY=0.679;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="304.0500000000002" y="569.9999999999999" as="sourcePoint"/>
<mxPoint x="665.0000000000005" y="569.9999999999999" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="68" value="&lt;span style=&quot;color: rgb(163 , 21 , 21) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px&quot;&gt;/token&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" vertex="1" connectable="0" parent="67">
<mxGeometry x="0.0583" y="1" relative="1" as="geometry">
<mxPoint x="-5" y="1" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="69" value="" style="endArrow=classic;html=1;fontSize=22;exitX=0;exitY=0.679;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.995;entryY=0.679;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="665.9500000000005" y="599.9999999999999" as="sourcePoint"/>
<mxPoint x="305.00000000000017" y="599.9999999999999" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="70" value="Access Token" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" vertex="1" connectable="0" parent="69">
<mxGeometry x="0.0583" y="1" relative="1" as="geometry">
<mxPoint x="26" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="71" value="" style="edgeStyle=none;html=1;entryX=-0.012;entryY=0.384;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-530" y="760" as="sourcePoint"/>
<mxPoint x="115.00000000000031" y="759.9999999999999" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="72" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;font color=&quot;#a31515&quot;&gt;Request with OKTA mechanism&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="71">
<mxCell id="34" value="&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; font-size: 12px ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;font color=&quot;#a31515&quot;&gt;Request with Access Token&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="33">
<mxGeometry x="-0.1257" y="2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -25,7 +25,7 @@ LDAP_USERS_BASE_DN = <ou=users,dc=cloudron>
LDAP_GROUPS_BASE_DN = <ou=groups,dc=cloudron>
#default value is 100
MAX_WRONG_ATTEMPTS_BY_IP_PER_DAY=100
MAX_WRONG_ATTEMPTS_BY_IP_PER_DAY=100
#default value is 10
MAX_CONSECUTIVE_FAILS_BY_USERNAME_AND_IP=10

4659
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,10 +18,10 @@
"lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
"exe": "npm run build && pkg .",
"copy:files": "npm run public:copy && npm run sasjsbuild:copy && npm run sas:copy && npm run web:copy",
"public:copy": "cp -r ./public/ ./build/public/",
"sasjsbuild:copy": "cp -r ./sasjsbuild/ ./build/sasjsbuild/",
"sas:copy": "cp -r ./sas/ ./build/sas/",
"web:copy": "rimraf web && mkdir web && cp -r ../web/build/ ./web/build/",
"public:copy": "cpr ./public/ ./build/public/",
"sasjsbuild:copy": "cpr ./sasjsbuild/ ./build/sasjsbuild/",
"sas:copy": "cpr ./sas/ ./build/sas/",
"web:copy": "rimraf web && mkdir web && cpr ../web/build/ ./web/build/",
"compileSysInit": "ts-node ./scripts/compileSysInit.ts",
"copySASjsCore": "ts-node ./scripts/copySASjsCore.ts",
"downloadMacros": "ts-node ./scripts/downloadMacros.ts"
@@ -58,7 +58,7 @@
"express-session": "^1.17.2",
"helmet": "^5.0.2",
"joi": "^17.4.2",
"jsonwebtoken": "^8.5.1",
"jsonwebtoken": "^9.0.2",
"ldapjs": "2.3.3",
"mongoose": "^6.0.12",
"morgan": "^1.10.0",
@@ -87,15 +87,16 @@
"@types/unzipper": "^0.10.5",
"adm-zip": "^0.5.9",
"axios": "0.27.2",
"cpr": "^3.0.1",
"csrf": "^3.1.0",
"dotenv": "^16.0.1",
"dotenv": "^10.0.0",
"http-headers-validation": "^0.0.1",
"jest": "^27.0.6",
"mongodb-memory-server": "8.11.4",
"nodejs-file-downloader": "4.10.2",
"nodemon": "^2.0.7",
"pkg": "5.6.0",
"prettier": "^2.3.1",
"prettier": "^3.0.3",
"rimraf": "^3.0.2",
"supertest": "^6.1.3",
"ts-jest": "^27.0.3",

View File

@@ -98,47 +98,17 @@ components:
properties:
code:
type: string
description: 'The code to be executed'
example: '* Your Code HERE;'
description: 'Code of program'
example: '* Code HERE;'
runTime:
$ref: '#/components/schemas/RunTimeType'
description: 'The runtime for the code - eg SAS, JS, PY or R'
description: 'runtime for program'
example: js
required:
- code
- runTime
type: object
additionalProperties: false
TriggerCodeResponse:
properties:
sessionId:
type: string
description: "The SessionId is the name of the temporary folder used to store the outputs.\nFor SAS, this would be the SASWORK folder. Can be used to poll job status.\nThis session ID should be used to poll job status."
example: '{ sessionId: ''20241028074744-54132-1730101664824'' }'
required:
- sessionId
type: object
additionalProperties: false
TriggerCodePayload:
properties:
code:
type: string
description: 'The code to be executed'
example: '* Your Code HERE;'
runTime:
$ref: '#/components/schemas/RunTimeType'
description: 'The runtime for the code - eg SAS, JS, PY or R'
example: sas
expiresAfterMins:
type: number
format: double
description: "Amount of minutes after the completion of the job when the session must be\ndestroyed."
example: 15
required:
- code
- runTime
type: object
additionalProperties: false
MemberType.folder:
enum:
- folder
@@ -593,16 +563,6 @@ components:
example: /Public/somefolder/some.file
type: object
additionalProperties: false
TriggerProgramResponse:
properties:
sessionId:
type: string
description: "The SessionId is the name of the temporary folder used to store the outputs.\nFor SAS, this would be the SASWORK folder. Can be used to poll program status.\nThis session ID should be used to poll program status."
example: '{ sessionId: ''20241028074744-54132-1730101664824'' }'
required:
- sessionId
type: object
additionalProperties: false
LoginPayload:
properties:
username:
@@ -845,30 +805,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ExecuteCodePayload'
/SASjsApi/code/trigger:
post:
operationId: TriggerCode
responses:
'200':
description: Ok
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerCodeResponse'
description: 'Trigger Code on the Specified Runtime'
summary: 'Triggers code and returns SessionId immediately - does not wait for job completion'
tags:
- Code
security:
-
bearerAuth: []
parameters: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerCodePayload'
/SASjsApi/drive/deploy:
post:
operationId: Deploy
@@ -1862,7 +1798,7 @@ paths:
bearerAuth: []
parameters:
-
description: 'Location of Stored Program in SASjs Drive.'
description: 'Location of code in SASjs Drive'
in: query
name: _program
required: true
@@ -1870,7 +1806,7 @@ paths:
type: string
example: /Projects/myApp/some/program
-
description: 'Optional query param for setting debug mode (returns the session log in the response body).'
description: 'Optional query param for setting debug mode, which will return the session log.'
in: query
name: _debug
required: false
@@ -1911,50 +1847,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ExecutePostRequestPayload'
/SASjsApi/stp/trigger:
post:
operationId: TriggerProgram
responses:
'200':
description: Ok
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerProgramResponse'
description: 'Trigger Program on the Specified Runtime.'
summary: 'Triggers program and returns SessionId immediately - does not wait for program completion.'
tags:
- STP
security:
-
bearerAuth: []
parameters:
-
description: 'Location of code in SASjs Drive.'
in: query
name: _program
required: true
schema:
type: string
example: /Projects/myApp/some/program
-
description: 'Optional query param for setting debug mode.'
in: query
name: _debug
required: false
schema:
format: double
type: number
example: 131
-
description: 'Optional query param for setting amount of minutes after the completion of the program when the session must be destroyed.'
in: query
name: expiresAfterMins
required: false
schema:
format: double
type: number
example: 15
/:
get:
operationId: Home

View File

@@ -1,55 +1,27 @@
import express from 'express'
import { Request, Security, Route, Tags, Post, Body } from 'tsoa'
import { ExecutionController, getSessionController } from './internal'
import { ExecutionController } from './internal'
import {
getPreProgramVariables,
getUserAutoExec,
ModeType,
parseLogToArray,
RunTimeType
} from '../utils'
interface ExecuteCodePayload {
/**
* The code to be executed
* @example "* Your Code HERE;"
* Code of program
* @example "* Code HERE;"
*/
code: string
/**
* The runtime for the code - eg SAS, JS, PY or R
* runtime for program
* @example "js"
*/
runTime: RunTimeType
}
interface TriggerCodePayload {
/**
* The code to be executed
* @example "* Your Code HERE;"
*/
code: string
/**
* The runtime for the code - eg SAS, JS, PY or R
* @example "sas"
*/
runTime: RunTimeType
/**
* Amount of minutes after the completion of the job when the session must be
* destroyed.
* @example 15
*/
expiresAfterMins?: number
}
interface TriggerCodeResponse {
/**
* The SessionId is the name of the temporary folder used to store the outputs.
* For SAS, this would be the SASWORK folder. Can be used to poll job status.
* This session ID should be used to poll job status.
* @example "{ sessionId: '20241028074744-54132-1730101664824' }"
*/
sessionId: string
}
@Security('bearerAuth')
@Route('SASjsApi/code')
@Tags('Code')
@@ -72,18 +44,6 @@ export class CodeController {
): Promise<string | Buffer> {
return executeCode(request, body)
}
/**
* Trigger Code on the Specified Runtime
* @summary Triggers code and returns SessionId immediately - does not wait for job completion
*/
@Post('/trigger')
public async triggerCode(
@Request() request: express.Request,
@Body() body: TriggerCodePayload
): Promise<TriggerCodeResponse> {
return triggerCode(request, body)
}
}
const executeCode = async (
@@ -116,49 +76,3 @@ const executeCode = async (
}
}
}
const triggerCode = async (
req: express.Request,
{ code, runTime, expiresAfterMins }: TriggerCodePayload
): Promise<TriggerCodeResponse> => {
const { user } = req
const userAutoExec =
process.env.MODE === ModeType.Server
? user?.autoExec
: await getUserAutoExec()
// get session controller based on runTime
const sessionController = getSessionController(runTime)
// get session
const session = await sessionController.getSession()
// add expiresAfterMins to session if provided
if (expiresAfterMins) {
// expiresAfterMins.used is set initially to false
session.expiresAfterMins = { mins: expiresAfterMins, used: false }
}
try {
// call executeProgram method of ExecutionController without awaiting
new ExecutionController().executeProgram({
program: code,
preProgramVariables: getPreProgramVariables(req),
vars: { ...req.query, _debug: 131 },
otherArgs: { userAutoExec },
runTime: runTime,
includePrintOutput: true,
session // session is provided
})
// return session id
return { sessionId: session.id }
} catch (err: any) {
throw {
code: 400,
status: 'failure',
message: 'Job execution failed.',
error: typeof err === 'object' ? err.toString() : err
}
}
}

View File

@@ -14,7 +14,8 @@ import {
createFile,
fileExists,
generateTimestamp,
readFile
readFile,
isWindows
} from '@sasjs/utils'
const execFilePromise = promisify(execFile)
@@ -193,29 +194,12 @@ ${autoExecContent}`
async () => {
if (session.inUse) {
// adding 10 more minutes
const newDeathTimeStamp =
parseInt(session.deathTimeStamp) + 10 * 60 * 1000
const newDeathTimeStamp = parseInt(session.deathTimeStamp) + 10 * 1000
session.deathTimeStamp = newDeathTimeStamp.toString()
this.scheduleSessionDestroy(session)
} else {
const { expiresAfterMins } = session
// delay session destroy if expiresAfterMins present
if (expiresAfterMins && !expiresAfterMins.used) {
// calculate session death time using expiresAfterMins
const newDeathTimeStamp =
parseInt(session.deathTimeStamp) +
expiresAfterMins.mins * 60 * 1000
session.deathTimeStamp = newDeathTimeStamp.toString()
// set expiresAfterMins to true to avoid using it again
session.expiresAfterMins!.used = true
this.scheduleSessionDestroy(session)
} else {
await this.deleteSession(session)
}
await this.deleteSession(session)
}
},
parseInt(session.deathTimeStamp) - new Date().getTime() - 100

View File

@@ -15,7 +15,7 @@ export const createJSProgram = async (
) => {
const varStatments = Object.keys(vars).reduce(
(computed: string, key: string) =>
`${computed}const ${key} = \`${vars[key]}\`;\n`,
`${computed}const ${key} = '${vars[key]}';\n`,
''
)

View File

@@ -1,16 +1,13 @@
import express from 'express'
import { Request, Security, Route, Tags, Post, Body, Get, Query } from 'tsoa'
import {
ExecutionController,
ExecutionVars,
getSessionController
} from './internal'
import { ExecutionController, ExecutionVars } from './internal'
import {
getPreProgramVariables,
makeFilesNamesMap,
getRunTimeAndFilePath
} from '../utils'
import { MulterFile } from '../types/Upload'
import { debug } from 'console'
interface ExecutePostRequestPayload {
/**
@@ -20,34 +17,6 @@ interface ExecutePostRequestPayload {
_program?: string
}
interface TriggerProgramPayload {
/**
* Location of SAS program.
* @example "/Public/somefolder/some.file"
*/
_program: string
/**
* Amount of minutes after the completion of the program when the session must be
* destroyed.
* @example 15
*/
expiresAfterMins?: number
/**
* Query param for setting debug mode.
*/
_debug?: number
}
interface TriggerProgramResponse {
/**
* The SessionId is the name of the temporary folder used to store the outputs.
* For SAS, this would be the SASWORK folder. Can be used to poll program status.
* This session ID should be used to poll program status.
* @example "{ sessionId: '20241028074744-54132-1730101664824' }"
*/
sessionId: string
}
@Security('bearerAuth')
@Route('SASjsApi/stp')
@Tags('STP')
@@ -61,8 +30,8 @@ export class STPController {
* https://server.sasjs.io/storedprograms
*
* @summary Execute a Stored Program, returns _webout and (optionally) log.
* @param _program Location of Stored Program in SASjs Drive.
* @param _debug Optional query param for setting debug mode (returns the session log in the response body).
* @param _program Location of code in SASjs Drive
* @param _debug Optional query param for setting debug mode, which will return the session log.
* @example _program "/Projects/myApp/some/program"
* @example _debug 131
*/
@@ -110,26 +79,6 @@ export class STPController {
return execute(request, program!, vars, otherArgs)
}
/**
* Trigger Program on the Specified Runtime.
* @summary Triggers program and returns SessionId immediately - does not wait for program completion.
* @param _program Location of code in SASjs Drive.
* @param expiresAfterMins Optional query param for setting amount of minutes after the completion of the program when the session must be destroyed.
* @param _debug Optional query param for setting debug mode.
* @example _program "/Projects/myApp/some/program"
* @example _debug 131
* @example expiresAfterMins 15
*/
@Post('/trigger')
public async triggerProgram(
@Request() request: express.Request,
@Query() _program: string,
@Query() _debug?: number,
@Query() expiresAfterMins?: number
): Promise<TriggerProgramResponse> {
return triggerProgram(request, { _program, _debug, expiresAfterMins })
}
}
const execute = async (
@@ -168,52 +117,3 @@ const execute = async (
}
}
}
const triggerProgram = async (
req: express.Request,
{ _program, _debug, expiresAfterMins }: TriggerProgramPayload
): Promise<TriggerProgramResponse> => {
try {
// put _program query param into vars object
const vars: { [key: string]: string | number } = { _program }
// if present add _debug query param to vars object
if (_debug) {
vars._debug = _debug
}
// get code path and runTime
const { codePath, runTime } = await getRunTimeAndFilePath(_program)
// get session controller based on runTime
const sessionController = getSessionController(runTime)
// get session
const session = await sessionController.getSession()
// add expiresAfterMins to session if provided
if (expiresAfterMins) {
// expiresAfterMins.used is set initially to false
session.expiresAfterMins = { mins: expiresAfterMins, used: false }
}
// call executeFile method of ExecutionController without awaiting
new ExecutionController().executeFile({
programPath: codePath,
runTime,
preProgramVariables: getPreProgramVariables(req),
vars,
session
})
// return session id
return { sessionId: session.id }
} catch (err: any) {
throw {
code: 400,
status: 'failure',
message: 'Job execution failed.',
error: typeof err === 'object' ? err.toString() : err
}
}
}

View File

@@ -285,7 +285,7 @@ const getUser = async (
username: user.username,
isActive: user.isActive,
isAdmin: user.isAdmin,
autoExec: getAutoExec ? (user.autoExec ?? '') : undefined,
autoExec: getAutoExec ? user.autoExec ?? '' : undefined,
groups: user.groups
}
}

View File

@@ -1,5 +1,5 @@
import express from 'express'
import { runCodeValidation, triggerCodeValidation } from '../../utils'
import { runCodeValidation } from '../../utils'
import { CodeController } from '../../controllers/'
const runRouter = express.Router()
@@ -28,22 +28,4 @@ runRouter.post('/execute', async (req, res) => {
}
})
runRouter.post('/trigger', async (req, res) => {
const { error, value: body } = triggerCodeValidation(req.body)
if (error) return res.status(400).send(error.details[0].message)
try {
const response = await controller.triggerCode(req, body)
res.status(200)
res.send(response)
} catch (err: any) {
const statusCode = err.code
delete err.code
res.status(statusCode).send(err)
}
})
export default runRouter

View File

@@ -1,8 +1,5 @@
import express from 'express'
import {
executeProgramRawValidation,
triggerProgramValidation
} from '../../utils'
import { executeProgramRawValidation } from '../../utils'
import { STPController } from '../../controllers/'
import { FileUploadController } from '../../controllers/internal'
@@ -72,28 +69,4 @@ stpRouter.post(
}
)
stpRouter.post('/trigger', async (req, res) => {
const { error, value: query } = triggerProgramValidation(req.query)
if (error) return res.status(400).send(error.details[0].message)
try {
const response = await controller.triggerProgram(
req,
query._program,
query._debug,
query.expiresAfterMins
)
res.status(200)
res.send(response)
} catch (err: any) {
const statusCode = err.code
delete err.code
res.status(statusCode).send(err)
}
})
export default stpRouter

View File

@@ -8,5 +8,4 @@ export interface Session {
consumed: boolean
completed: boolean
crashed?: string
expiresAfterMins?: { mins: number; used: boolean }
}

View File

@@ -1,31 +1,9 @@
import path from 'path'
import {
createFolder,
getAbsolutePath,
getRealPath,
fileExists
} from '@sasjs/utils'
import dotenv from 'dotenv'
import { createFolder, getAbsolutePath, getRealPath } from '@sasjs/utils'
import { connectDB, getDesktopFields, ModeType, RunTimeType, SECRETS } from '.'
export const setProcessVariables = async () => {
const { execPath } = process
// Check if execPath ends with 'api-macos' to determine executable for MacOS.
// This is needed to fix picking .env file issue in MacOS executable.
if (execPath) {
const envPathSplitted = execPath.split(path.sep)
if (envPathSplitted.pop() === 'api-macos') {
const envPath = path.join(envPathSplitted.join(path.sep), '.env')
// Override environment variables from envPath if file exists
if (await fileExists(envPath)) {
dotenv.config({ path: envPath, override: true })
}
}
}
const { MODE, RUN_TIMES } = process.env
if (MODE === ModeType.Server) {
@@ -43,7 +21,6 @@ export const setProcessVariables = async () => {
if (process.env.NODE_ENV === 'test') {
process.sasjsRoot = path.join(process.cwd(), 'sasjs_root')
process.driveLoc = path.join(process.cwd(), 'sasjs_root', 'drive')
return
}
@@ -64,9 +41,7 @@ export const setProcessVariables = async () => {
const { SASJS_ROOT } = process.env
const absPath = getAbsolutePath(SASJS_ROOT ?? 'sasjs_root', process.cwd())
await createFolder(absPath)
process.sasjsRoot = getRealPath(absPath)
const { DRIVE_LOCATION } = process.env
@@ -74,7 +49,6 @@ export const setProcessVariables = async () => {
DRIVE_LOCATION ?? path.join(process.sasjsRoot, 'drive'),
process.cwd()
)
await createFolder(absDrivePath)
process.driveLoc = getRealPath(absDrivePath)
@@ -83,9 +57,7 @@ export const setProcessVariables = async () => {
LOG_LOCATION ?? path.join(process.sasjsRoot, 'logs'),
process.cwd()
)
await createFolder(absLogsPath)
process.logsLoc = getRealPath(absLogsPath)
process.logsUUID = 'SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784'

View File

@@ -178,13 +178,6 @@ export const runCodeValidation = (data: any): Joi.ValidationResult =>
runTime: Joi.string().valid(...process.runTimes)
}).validate(data)
export const triggerCodeValidation = (data: any): Joi.ValidationResult =>
Joi.object({
code: Joi.string().required(),
runTime: Joi.string().valid(...process.runTimes),
expiresAfterMins: Joi.number().greater(0)
}).validate(data)
export const executeProgramRawValidation = (data: any): Joi.ValidationResult =>
Joi.object({
_program: Joi.string().required(),
@@ -192,12 +185,3 @@ export const executeProgramRawValidation = (data: any): Joi.ValidationResult =>
})
.pattern(/^/, Joi.alternatives(Joi.string(), Joi.number()))
.validate(data)
export const triggerProgramValidation = (data: any): Joi.ValidationResult =>
Joi.object({
_program: Joi.string().required(),
_debug: Joi.number(),
expiresAfterMins: Joi.number().greater(0)
})
.pattern(/^/, Joi.alternatives(Joi.string(), Joi.number()))
.validate(data)

21
web/package-lock.json generated
View File

@@ -56,7 +56,7 @@
"file-loader": "^6.2.0",
"html-webpack-plugin": "5.5.0",
"path": "0.12.7",
"prettier": "^2.4.1",
"prettier": "^3.0.3",
"sass": "^1.44.0",
"sass-loader": "^12.3.0",
"style-loader": "^3.3.1",
@@ -9413,15 +9413,18 @@
}
},
"node_modules/prettier": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
"integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
"integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=10.13.0"
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-error": {
@@ -18615,9 +18618,9 @@
"dev": true
},
"prettier": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
"integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
"integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
"dev": true
},
"pretty-error": {

View File

@@ -4,7 +4,9 @@
"private": true,
"scripts": {
"start": "webpack-dev-server --config webpack.dev.ts --hot",
"build": "webpack --config webpack.prod.ts"
"build": "webpack --config webpack.prod.ts",
"lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
"lint:fix": "npx prettier --write \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\""
},
"dependencies": {
"@emotion/react": "^11.4.1",
@@ -55,7 +57,7 @@
"file-loader": "^6.2.0",
"html-webpack-plugin": "5.5.0",
"path": "0.12.7",
"prettier": "^2.4.1",
"prettier": "^3.0.3",
"sass": "^1.44.0",
"sass-loader": "^12.3.0",
"style-loader": "^3.3.1",