Secure grapesJs services, improve their logic, add notes
Showing
2 changed files
with
76 additions
and
62 deletions
... | @@ -171,7 +171,7 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -171,7 +171,7 @@ along with this software (see the LICENSE.md file). If not, see |
171 | window.emailTemplateId = new URLSearchParams(window.location.search).get('emailTemplateId'); | 171 | window.emailTemplateId = new URLSearchParams(window.location.search).get('emailTemplateId'); |
172 | 172 | ||
173 | const request = new XMLHttpRequest(); | 173 | const request = new XMLHttpRequest(); |
174 | request.open("GET", ("${baseLinkUrl}/rest/s1/moqui-mjml/mjml?grapesLocation="+window.grapesLocation+"&htmlLocation="+window.htmlLocation+"&emailTemplateId="+window.emailTemplateId), false); // `false` makes the request synchronous | 174 | request.open("GET", ("${baseLinkUrl}/rest/s1/moqui-mjml/mjml?emailTemplateId="+window.emailTemplateId), false); // `false` makes the request synchronous |
175 | request.send(null); | 175 | request.send(null); |
176 | 176 | ||
177 | let response; | 177 | let response; |
... | @@ -203,8 +203,8 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -203,8 +203,8 @@ along with this software (see the LICENSE.md file). If not, see |
203 | // Default storage options | 203 | // Default storage options |
204 | options: { | 204 | options: { |
205 | remote: { | 205 | remote: { |
206 | urlLoad: "${baseLinkUrl}/rest/s1/moqui-mjml/mjml?grapesLocation="+window.grapesLocation+"&htmlLocation="+window.htmlLocation, | 206 | urlLoad: "${baseLinkUrl}/rest/s1/moqui-mjml/mjml?emailTemplateId="+window.emailTemplateId, |
207 | urlStore: "${baseLinkUrl}/rest/s1/moqui-mjml/mjml?grapesLocation="+window.grapesLocation+"&htmlLocation="+window.htmlLocation, | 207 | urlStore: "${baseLinkUrl}/rest/s1/moqui-mjml/mjml?emailTemplateId="+window.emailTemplateId, |
208 | headers: { | 208 | headers: { |
209 | "X-CSRF-Token": document.getElementById('confMoquiSessionToken').value | 209 | "X-CSRF-Token": document.getElementById('confMoquiSessionToken').value |
210 | }, | 210 | }, |
... | @@ -222,9 +222,11 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -222,9 +222,11 @@ along with this software (see the LICENSE.md file). If not, see |
222 | const url = new URL(window.location.href) | 222 | const url = new URL(window.location.href) |
223 | url.searchParams.set('grapesLocation', result.grapesLocation); | 223 | url.searchParams.set('grapesLocation', result.grapesLocation); |
224 | url.searchParams.set('htmlLocation', result.htmlLocation); | 224 | url.searchParams.set('htmlLocation', result.htmlLocation); |
225 | url.searchParams.set('emailTemplateId', result.emailTemplateId); | ||
225 | window.history.pushState({}, '', url) | 226 | window.history.pushState({}, '', url) |
226 | window.grapesLocation = result.grapesLocation; | 227 | window.grapesLocation = result.grapesLocation; |
227 | window.htmlLocation = result.htmlLocation; | 228 | window.htmlLocation = result.htmlLocation; |
229 | window.emailTemplateId = result.emailTemplateId; | ||
228 | } | 230 | } |
229 | // console.log('onLoad ', result) | 231 | // console.log('onLoad ', result) |
230 | return result.data | 232 | return result.data | ... | ... |
... | @@ -15,11 +15,11 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -15,11 +15,11 @@ along with this software (see the LICENSE.md file). If not, see |
15 | <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-3.xsd"> | 15 | <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-3.xsd"> |
16 | 16 | ||
17 | <service verb="load" noun="GrapeJs"> | 17 | <service verb="load" noun="GrapeJs"> |
18 | <description>Create MJML</description> | 18 | <description>Load GrapesJs resource. Can be adapted to entity other than EmailTemplate, but must have data for the grapesLocation and htmlLocation to ensure safety of read and write of resources.</description> |
19 | <in-parameters> | 19 | <in-parameters> |
20 | <parameter name="grapesLocation"/> | 20 | <parameter name="grapesLocation"/> |
21 | <parameter name="htmlLocation"/> | 21 | <parameter name="htmlLocation"/> |
22 | <parameter name="emailTemplateId"/> | 22 | <parameter name="emailTemplateId" required="true"/> |
23 | </in-parameters> | 23 | </in-parameters> |
24 | <out-parameters> | 24 | <out-parameters> |
25 | <parameter name="grapesLocation"/> | 25 | <parameter name="grapesLocation"/> |
... | @@ -31,21 +31,10 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -31,21 +31,10 @@ along with this software (see the LICENSE.md file). If not, see |
31 | <if condition="htmlLocation == 'null'"><set field="htmlLocation" from="null"/></if> | 31 | <if condition="htmlLocation == 'null'"><set field="htmlLocation" from="null"/></if> |
32 | <!-- <log level="warn" message="resourceId is ${resourceId} resourceId.getClass().getName() ${resourceId.getClass().getName()} resourceId == 'null' ${resourceId == 'null'} resourceId == null ${resourceId == null}"/>--> | 32 | <!-- <log level="warn" message="resourceId is ${resourceId} resourceId.getClass().getName() ${resourceId.getClass().getName()} resourceId == 'null' ${resourceId == 'null'} resourceId == null ${resourceId == null}"/>--> |
33 | <!-- <log level="warn" message="load context.toString() ${context.toString()}"/>--> | 33 | <!-- <log level="warn" message="load context.toString() ${context.toString()}"/>--> |
34 | <if condition="emailTemplateId"> | 34 | <entity-find-one entity-name="moqui.basic.email.EmailTemplate" value-field="emailTemplate" auto-field-map="[emailTemplateId:emailTemplateId]"/> |
35 | <entity-find-one entity-name="moqui.basic.email.EmailTemplate" value-field="emailTemplate" auto-field-map="[emailTemplateId:emailTemplateId]"/> | 35 | <if condition="!emailTemplate"><return error="true" message="Resource not found"/></if> |
36 | <if condition="!grapesLocation"><set field="grapesLocation" from="emailTemplate?.grapesLocation"/></if> | 36 | <set field="grapesLocation" from="emailTemplate?.grapesLocation"/> |
37 | <if condition="grapesLocation && grapesLocation != emailTemplate?.grapesLocation"> | 37 | <set field="htmlLocation" from="emailTemplate?.htmlLocation"/> |
38 | <!-- This should almost never happen, but if it does it basically creates a resource leak for the previously used resource --> | ||
39 | <log message="Changing resource id from ${grapesLocation} to ${emailTemplate?.grapesLocation} for email template ${emailTemplateId}"/> | ||
40 | <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,grapesLocation:grapesLocation]"/> | ||
41 | </if> | ||
42 | <if condition="!htmlLocation"><set field="htmlLocation" from="emailTemplate?.htmlLocation"/></if> | ||
43 | <if condition="htmlLocation && htmlLocation != emailTemplate?.htmlLocation"> | ||
44 | <!-- This should almost never happen, but if it does it basically creates a resource leak for the previously used resource --> | ||
45 | <log message="Changing resource id from ${htmlLocation} to ${emailTemplate?.htmlLocation} for email template ${emailTemplateId}"/> | ||
46 | <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,htmlLocation:htmlLocation]"/> | ||
47 | </if> | ||
48 | </if> | ||
49 | 38 | ||
50 | <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/> | 39 | <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/> |
51 | <if condition="!grapesLocation && !htmlLocation"> | 40 | <if condition="!grapesLocation && !htmlLocation"> |
... | @@ -62,11 +51,9 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -62,11 +51,9 @@ along with this software (see the LICENSE.md file). If not, see |
62 | grapesFile.move(grapesLocation) | 51 | grapesFile.move(grapesLocation) |
63 | ]]></script> | 52 | ]]></script> |
64 | 53 | ||
65 | <if condition="emailTemplateId"> | 54 | <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,grapesLocation:grapesLocation,htmlLocation:htmlLocation]"/> |
66 | <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,grapesLocation:grapesLocation,htmlLocation:htmlLocation]"/> | ||
67 | </if> | ||
68 | </then> | 55 | </then> |
69 | <else> | 56 | <else-if condition="grapesLocation && htmlLocation"> |
70 | <set field="putDbResource" from="ec.resource.getLocationReference(grapesLocation)"/> | 57 | <set field="putDbResource" from="ec.resource.getLocationReference(grapesLocation)"/> |
71 | <!-- TODO: Is this a strong enough check to prevent unauthorized access? --> | 58 | <!-- TODO: Is this a strong enough check to prevent unauthorized access? --> |
72 | <if condition="!putDbResource || putDbResource.parent?.location != grapesJsResource.location"> | 59 | <if condition="!putDbResource || putDbResource.parent?.location != grapesJsResource.location"> |
... | @@ -74,65 +61,90 @@ along with this software (see the LICENSE.md file). If not, see | ... | @@ -74,65 +61,90 @@ along with this software (see the LICENSE.md file). If not, see |
74 | </if> | 61 | </if> |
75 | 62 | ||
76 | <set field="data" from="putDbResource.getText()"/> | 63 | <set field="data" from="putDbResource.getText()"/> |
64 | </else-if> | ||
65 | <else> | ||
66 | <return error="true" message="Resource not found"/> | ||
77 | </else> | 67 | </else> |
78 | </if> | 68 | </if> |
79 | </actions> | 69 | </actions> |
80 | </service> | 70 | </service> |
81 | <service verb="store" noun="GrapeJs" authenticate="anonymous-all"> | 71 | <service verb="store" noun="GrapeJs" authenticate="anonymous-all"> |
82 | <description>Create MJML</description> | 72 | <description>Store GrapesJs resource. Can be adapted to entity other than EmailTemplate, but must have data for the grapesLocation and htmlLocation to ensure safety of read and write of resources.</description> |
83 | <in-parameters> | 73 | <in-parameters> |
84 | <parameter name="resourceId"/> | 74 | <parameter name="htmlLocation"/> |
75 | <parameter name="grapesLocation"/> | ||
76 | <parameter name="emailTemplateId"/> | ||
85 | <parameter name="data"/> | 77 | <parameter name="data"/> |
86 | <parameter name="html" allow-html="any"/> | 78 | <parameter name="html" allow-html="any"/> |
87 | </in-parameters> | 79 | </in-parameters> |
88 | <out-parameters> | 80 | <out-parameters> |
89 | <parameter name="resourceId"/> | 81 | <parameter name="htmlLocation"/> |
82 | <parameter name="grapesLocation"/> | ||
90 | </out-parameters> | 83 | </out-parameters> |
91 | <actions> | 84 | <actions> |
92 | <if condition="resourceId == 'null'"><set field="resourceId" from="null"/></if> | 85 | <if condition="htmlLocation == 'null'"><set field="htmlLocation" from="null"/></if> |
86 | <if condition="grapesLocation == 'null'"><set field="grapesLocation" from="null"/></if> | ||
87 | <entity-find-one entity-name="moqui.basic.email.EmailTemplate" value-field="emailTemplate" auto-field-map="[emailTemplateId:emailTemplateId]"/> | ||
88 | <if condition="!emailTemplate"><return error="true" message="Resource not found"/></if> | ||
89 | <set field="grapesLocation" from="emailTemplate?.grapesLocation"/> | ||
90 | <set field="htmlLocation" from="emailTemplate?.htmlLocation"/> | ||
93 | <set field="data" from="groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parseText(ec.web.secureRequestParameters._requestBodyText).data)"/> | 91 | <set field="data" from="groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parseText(ec.web.secureRequestParameters._requestBodyText).data)"/> |
94 | 92 | ||
95 | <if condition="!resourceId"> | 93 | <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/> |
94 | <if condition="!htmlLocation && !grapesLocation"> | ||
96 | <then> | 95 | <then> |
97 | <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/> | 96 | <!-- TODO: This should work, but isn't used anywhere and is untested. |
98 | <service-call name="create#moqui.resource.DbResource" in-map="[parentResourceId:grapesJsResource.getDbResourceId(),isFile:'Y']" out-map="dbResource"/> | 97 | <set field="htmlFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.html')"/> |
99 | <service-call name="update#moqui.resource.DbResource" in-map="[resourceId:dbResource.resourceId,filename:dbResource.resourceId+'.json']" out-map="dbResource"/> | 98 | <set field="grapesFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.json')"/> |
100 | <set field="versionName" value="01"/> | ||
101 | <service-call name="create#moqui.resource.DbResourceFile" in-map="[resourceId: dbResource.resourceId,mimeType: 'text/json',versionName: versionName,rootVersionName: versionName,fileData:data]"/> | ||
102 | <service-call name="create#moqui.resource.DbResourceFileHistory" in-map="[resourceId: dbResource.resourceId,versionDate: ec.user.nowTimestamp,userId: ec.user.userId,isDiff: 'N']"/> | ||
103 | <set field="resourceId" from="dbResource.resourceId"/> | ||
104 | 99 | ||
105 | <set field="htmlFile" from="grapesJsResource.makeFile(resourceId.toString()+'.html')"/> | 100 | <set field="htmlLocation" from="grapesJsResource.location + '/' + htmlFile?.dbResourceId + '.html'"/> |
106 | <script><![CDATA[htmlFile.putText(html)]]></script> | 101 | <set field="grapesLocation" from="grapesJsResource.location + '/' + grapesFile?.dbResourceId + '.json'"/> |
102 | <if condition="ec.resource.getLocationReference(htmlLocation).parent?.location != grapesJsResource.location"> | ||
103 | <return error="true" message="Resource not found"/> | ||
104 | </if> | ||
105 | <if condition="ec.resource.getLocationReference(grapesLocation).parent?.location != grapesJsResource.location"> | ||
106 | <return error="true" message="Resource not found"/> | ||
107 | </if> | ||
108 | <script><![CDATA[ | ||
109 | htmlFile.putText(html) | ||
110 | htmlFile.move(htmlLocation) | ||
111 | grapesFile.putText(data) | ||
112 | grapesFile.move(grapesLocation) | ||
113 | ]]></script>--> | ||
114 | <return error="true" message="Resource not found"/> | ||
107 | </then> | 115 | </then> |
108 | <else> | 116 | <else-if condition="grapesLocation"> |
109 | <entity-find-one entity-name="moqui.resource.DbResource" value-field="dbResource" auto-field-map="[resourceId:resourceId]"/> | 117 | <set field="grapesFile" from="ec.resource.getLocationReference(grapesLocation)"/> |
110 | <if condition="!dbResource"> | 118 | <if condition="!grapesFile || grapesFile.parent?.location != grapesJsResource.location"> |
111 | <return error="true" message="Resource not found"/> | 119 | <return error="true" message="Resource not found"/> |
112 | </if> | 120 | </if> |
113 | <set field="actualDbResourcePath" from="null"/> | 121 | <script>grapesFile.putText(data)</script> |
114 | <set field="dbResourcePath" from="dbResource.filename"/> | ||
115 | <set field="lastDbResource" from="dbResource"/> | ||
116 | <script> | ||
117 | while (actualDbResourcePath == null) { | ||
118 | if (lastDbResource.parentResourceId == null) { | ||
119 | dbResourcePath = 'dbresource://'+dbResourcePath | ||
120 | actualDbResourcePath = dbResourcePath | ||
121 | } else { | ||
122 | lastDbResource = ec.entity.fastFindOne("moqui.resource.DbResource", true, false, lastDbResource.parentResourceId) | ||
123 | dbResourcePath = lastDbResource.filename+'/'+dbResourcePath | ||
124 | } | ||
125 | } | ||
126 | </script> | ||
127 | <set field="putDbResource" from="ec.resource.getLocationReference(actualDbResourcePath)"/> | ||
128 | <script> | ||
129 | putDbResource.putText(data) | ||
130 | </script> | ||
131 | 122 | ||
132 | <set field="grapesJsResource" from="ec.resource.getLocationReference('dbresource://grapesjs/project')"/> | 123 | <set field="htmlFile" from="null"/> |
133 | <set field="htmlFile" from="grapesJsResource.findChildFile(resourceId.toString()+'.html') ?: grapesJsResource.makeFile(resourceId.toString()+'.html')"/> | 124 | <if condition="htmlLocation"><then> |
134 | <script><![CDATA[htmlFile.putText(html)]]></script> | 125 | <set field="htmlFile" from="ec.resource.getLocationReference(htmlLocation)"/> |
126 | </then><else> | ||
127 | <entity-find entity-name="moqui.basic.email.EmailTemplate" list="emailTemplateList"> | ||
128 | <econdition field-name="grapesLocation"/> | ||
129 | <order-by field-name="-lastUpdatedStamp"/></entity-find> | ||
130 | <set field="emailTemplate" from="emailTemplateList.getFirst()"/> | ||
131 | <if condition="emailTemplateList.size() == 1 && emailTemplate.htmlLocation"><then> | ||
132 | <set field="htmlFile" from="ec.resource.getLocationReference(emailTemplate.htmlLocation)"/> | ||
133 | </then><else> | ||
134 | <set field="htmlFile" from="grapesJsResource.makeFile(java.util.UUID.randomUUID().toString()+'.html')"/> | ||
135 | <set field="htmlLocation" from="grapesJsResource.location + '/' + htmlFile?.dbResourceId + '.html'"/> | ||
136 | <script><![CDATA[htmlFile.move(htmlLocation)]]></script> | ||
|
|||
135 | 137 | ||
138 | <service-call name="update#moqui.basic.email.EmailTemplate" in-map="[emailTemplateId:emailTemplateId,htmlLocation:htmlLocation]"/> | ||
139 | </else></if> | ||
140 | </else></if> | ||
141 | <if condition="!htmlFile || htmlFile.parent?.location != grapesJsResource.location"> | ||
142 | <return error="true" message="Resource not found"/> | ||
143 | </if> | ||
144 | <script><![CDATA[htmlFile.putText(html)]]></script> | ||
145 | </else-if> | ||
146 | <else> | ||
147 | <return error="true" message="Resource not found"/> | ||
136 | </else> | 148 | </else> |
137 | </if> | 149 | </if> |
138 | </actions> | 150 | </actions> | ... | ... |
-
Please register or sign in to post a comment