8080import org .labkey .api .util .ErrorRenderer ;
8181import org .labkey .api .util .ExceptionUtil ;
8282import org .labkey .api .util .FileUtil ;
83+ import org .labkey .api .util .HtmlString ;
8384import org .labkey .api .util .JsonUtil ;
8485import org .labkey .api .util .Pair ;
8586import org .labkey .api .util .URLHelper ;
107108import java .util .Map ;
108109import java .util .Set ;
109110
111+ import static org .labkey .api .util .DOM .BR ;
112+ import static org .labkey .api .util .DOM .INPUT ;
113+ import static org .labkey .api .util .DOM .P ;
114+ import static org .labkey .api .util .DOM .TABLE ;
115+ import static org .labkey .api .util .DOM .TD ;
116+ import static org .labkey .api .util .DOM .TR ;
117+ import static org .labkey .api .util .DOM .at ;
118+ import static org .labkey .api .util .DOM .createHtmlFragment ;
119+ import static org .labkey .api .util .DOM .Attribute .style ;
120+
110121
111122public class LaboratoryController extends SpringActionController
112123{
@@ -127,13 +138,13 @@ public ModelAndView getView(PlanExptRunForm form, BindException errors) throws E
127138 Integer assayId = form .getAssayId ();
128139 if (assayId == null )
129140 {
130- return new HtmlView ("Error: must provide a rowId for the assay" );
141+ return new HtmlView (HtmlString . of ( "Error: must provide a rowId for the assay" ) );
131142 }
132143
133144 AssayDataProvider ad = LaboratoryService .get ().getDataProviderForAssay (assayId );
134145 if (ad == null || !ad .supportsRunTemplates ())
135146 {
136- return new HtmlView ("Error: this assay does not support requests" );
147+ return new HtmlView (HtmlString . of ( "Error: this assay does not support requests" ) );
137148 }
138149
139150 Module labModule = ModuleLoader .getInstance ().getModule (LaboratoryModule .NAME );
@@ -173,15 +184,13 @@ public void validateCommand(Object form, Errors errors)
173184 @ Override
174185 public ModelAndView getConfirmView (Object form , BindException errors ) throws Exception
175186 {
176- StringBuilder msg = new StringBuilder ();
177- msg .append ("Certain assays can have performance improved by the addition of indexes, which can be suggested by modules. The following indexes are recommended for the assays installed on this server:<p>" );
178-
179187 List <String > msgs = LaboratoryManager .get ().createIndexes (getUser (), false , false );
180- msg .append (StringUtils .join (msgs , "<br>" ));
181188
182- msg .append ("<p>Do you want to continue?" );
183-
184- return new HtmlView (msg .toString ());
189+ return new HtmlView (createHtmlFragment (
190+ "Certain assays can have performance improved by the addition of indexes, which can be suggested by modules. The following indexes are recommended for the assays installed on this server:" ,
191+ P (msgs .stream ().map (msg -> createHtmlFragment (msg , BR ()))),
192+ P ("Do you want to continue?" )
193+ ));
185194 }
186195
187196 @ Override
@@ -232,17 +241,12 @@ public ModelAndView getConfirmView(EnsureAssayFieldsForm form, BindException err
232241 {
233242 try
234243 {
235- StringBuilder sb = new StringBuilder ();
236- sb .append ("This action will iterate all protocols for the assay " + form .getProviderName () + " and append any columns present in the definition, but lacking from that instance of the assay. The following changes will be made:<br><br>" );
237244 List <String > messages = AssayHelper .ensureAssayFields (getUser (), form .getProviderName (), form .isRenameConflicts (), true );
238- for (String msg : messages )
239- {
240- sb .append (msg ).append ("<br><br>" );
241- }
242-
243- sb .append ("<br>Do you want to continue?" );
244-
245- return new HtmlView (sb .toString ());
245+ return new HtmlView (createHtmlFragment (
246+ "This action will iterate all protocols for the assay " + form .getProviderName () + " and append any columns present in the definition, but lacking from that instance of the assay. The following changes will be made:" , BR (), BR (),
247+ messages .stream ().map (msg -> createHtmlFragment (msg , BR (), BR ())),
248+ BR (), "Do you want to continue?"
249+ ));
246250 }
247251 catch (ChangePropertyDescriptorException e )
248252 {
@@ -308,25 +312,23 @@ public void validateCommand(SetTableIncrementForm form, Errors errors)
308312 @ Override
309313 public ModelAndView getConfirmView (SetTableIncrementForm form , BindException errors ) throws Exception
310314 {
311- StringBuilder sb = new StringBuilder ();
312- sb .append ("This allows you to reset the current value for an auto-incrementing table<br><br>" );
313- sb .append ("<table style='border-collapse: collapse;'>" );
314-
315315 String schema = form .getSchemaName () == null ? "" : form .getSchemaName ();
316- sb .append ("<tr><td>Schema:</td><td><input name=\" schema\" value=\" " + schema + "\" ></td></tr>" );
317-
318316 String query = form .getQueryName () == null ? "" : form .getQueryName ();
319- sb .append ("<tr><td>Query:</td><td><input name=\" query\" value=\" " + query + "\" ></td></tr>" );
320317
321318 ContainerIncrementingTable ti = getTable (schema , query , errors , false );
322- Integer value = null ;
319+ Integer currentId = null ;
323320 if (ti != null )
324- value = ti .getCurrentId (getContainer ());
325-
326- sb .append ("<tr><td>Value:</td><td><input name=\" value\" value=\" " + (value == null ? "" : value ) + "\" ></td></tr>" );
327- sb .append ("</table><br>Do you want to continue?" );
321+ currentId = ti .getCurrentId (getContainer ());
328322
329- return new HtmlView (sb .toString ());
323+ return new HtmlView (createHtmlFragment (
324+ "This allows you to reset the current value for an auto-incrementing table" , BR (), BR (),
325+ TABLE (at (style , "border-collapse: collapse;" ),
326+ TR (TD ("Schema:" ), TD (INPUT (at ().name ("schema" ).value (schema )))),
327+ TR (TD ("Query:" ), TD (INPUT (at ().name ("query" ).value (query )))),
328+ TR (TD ("Value:" ), TD (INPUT (at ().name ("value" ).value (currentId == null ? "" : currentId .toString ()))))
329+ ),
330+ BR (), "Do you want to continue?"
331+ ));
330332 }
331333
332334 @ Override
@@ -468,7 +470,7 @@ public void validateCommand(Object form, Errors errors)
468470 @ Override
469471 public ModelAndView getConfirmView (Object form , BindException errors ) throws Exception
470472 {
471- return new HtmlView ("This action will iterate all workbooks in the current folder and create laboratory experiments for them as needed" );
473+ return new HtmlView (HtmlString . of ( "This action will iterate all workbooks in the current folder and create laboratory experiments for them as needed" ) );
472474 }
473475
474476 @ Override
@@ -507,20 +509,18 @@ public void validateCommand(SetTableIncrementForm form, Errors errors)
507509 @ Override
508510 public ModelAndView getConfirmView (SetTableIncrementForm form , BindException errors ) throws Exception
509511 {
510- StringBuilder sb = new StringBuilder ();
511- sb .append ("This allows you to initialize the autoincrementing column for the provided schema/query<br><br>" );
512- sb .append ("This is very rarely required and was created as a helper for admins with a good deal of knowledge about this module. Under most cases these columns will be automatically populated and you will not need to worry about this. If you are unsure about this page, please post on the LabKey help forums, which are read by the authors of this module.<br><br>" );
513- sb .append ("<table style='border-collapse: collapse;'>" );
514-
515512 String schema = form .getSchemaName () == null ? "" : form .getSchemaName ();
516- sb .append ("<tr><td>Schema:</td><td><input name=\" schema\" value=\" " + schema + "\" ></td></tr>" );
517-
518513 String query = form .getQueryName () == null ? "" : form .getQueryName ();
519- sb .append ("<tr><td>Query:</td><td><input name=\" query\" value=\" " + query + "\" ></td></tr>" );
520514
521- sb .append ("</table><br>Do you want to continue?" );
522-
523- return new HtmlView (sb .toString ());
515+ return new HtmlView (createHtmlFragment (
516+ "This allows you to initialize the autoincrementing column for the provided schema/query" , BR (), BR (),
517+ "This is very rarely required and was created as a helper for admins with a good deal of knowledge about this module. Under most cases these columns will be automatically populated and you will not need to worry about this. If you are unsure about this page, please post on the LabKey help forums, which are read by the authors of this module." , BR (), BR (),
518+ TABLE (at (style , "border-collapse: collapse;" ),
519+ TR (TD ("Schema:" ), TD (INPUT (at ().name ("schema" ).value (schema )))),
520+ TR (TD ("Query:" ), TD (INPUT (at ().name ("query" ).value (query ))))
521+ ),
522+ BR (), "Do you want to continue?"
523+ ));
524524 }
525525
526526
@@ -579,7 +579,8 @@ public void validateCommand(Object form, Errors errors)
579579 @ Override
580580 public ModelAndView getConfirmView (Object form , BindException errors ) throws Exception
581581 {
582- return new HtmlView ("This action will reset webparts and tabs for the current folder and all children to the default Laboratory FolderType, if these folders are either Laboratory Folders or Expt Workbooks" );
582+ HtmlString message = HtmlString .of ("This action will reset webparts and tabs for the current folder and all children to the default Laboratory FolderType, if these folders are either Laboratory Folders or Expt Workbooks" );
583+ return new HtmlView (message );
583584 }
584585
585586 @ Override
@@ -647,8 +648,9 @@ public String getResponse(ProcessAssayForm form, Map<String, Pair<FileLike, Stri
647648 throw new UploadException ("No Assay Id Provided" , HttpServletResponse .SC_BAD_REQUEST );
648649 }
649650
651+ // getExpProtocol() is unscoped, so verify the protocol is in scope for this container before using it.
650652 ExpProtocol protocol = ExperimentService .get ().getExpProtocol (form .getLabkeyAssayId ());
651- if (protocol == null )
653+ if (protocol == null || ! AssayService . get (). getAssayProtocols ( getContainer ()). contains ( protocol ) )
652654 {
653655 throw new UploadException ("Unable to find assay protocol with Id: " + form .getLabkeyAssayId (), HttpServletResponse .SC_BAD_REQUEST );
654656 }
@@ -936,8 +938,9 @@ public ApiResponse execute(SaveTemplateForm form, BindException errors) throws E
936938 {
937939 JSONObject json = new JSONObject (form .getJson ());
938940
941+ // getExpProtocol() is unscoped, so verify the protocol is in scope for this container before saving a template against it.
939942 ExpProtocol protocol = ExperimentService .get ().getExpProtocol (form .getProtocolId ());
940- if (protocol == null )
943+ if (protocol == null || ! AssayService . get (). getAssayProtocols ( getContainer ()). contains ( protocol ) )
941944 {
942945 errors .reject (ERROR_MSG , "Unknown assay: " + form .getProtocolId ());
943946 return null ;
@@ -1063,8 +1066,9 @@ public void export(ProcessAssayForm form, HttpServletResponse response, BindExce
10631066 return ;
10641067 }
10651068
1069+ // getExpProtocol() is unscoped, so verify the protocol is in scope for this container before generating a template against it.
10661070 ExpProtocol protocol = ExperimentService .get ().getExpProtocol (form .getLabkeyAssayId ());
1067- if (protocol == null )
1071+ if (protocol == null || ! AssayService . get (). getAssayProtocols ( getContainer ()). contains ( protocol ) )
10681072 {
10691073 throw new AbstractFileUploadAction .UploadException ("Unable to find assay protocol with Id: " + form .getLabkeyAssayId (), HttpServletResponse .SC_BAD_REQUEST );
10701074 }
@@ -1514,8 +1518,9 @@ public ApiResponse execute(AssayImportHeadersForm form, BindException errors)
15141518 return new ApiSimpleResponse (results );
15151519 }
15161520
1521+ // getExpProtocol() is unscoped, so verify the protocol is in scope for this container before returning its import columns.
15171522 ExpProtocol protocol = ExperimentService .get ().getExpProtocol (form .getProtocol ());
1518- if (protocol == null )
1523+ if (protocol == null || ! AssayService . get (). getAssayProtocols ( getContainer ()). contains ( protocol ) )
15191524 {
15201525 errors .reject (ERROR_MSG , "Protocol not found: " + form .getProtocol ());
15211526 return new ApiSimpleResponse (results );
@@ -1916,8 +1921,16 @@ public ApiResponse execute(ImportMethodsForm form, BindException errors)
19161921 List <ExpProtocol > protocols = new ArrayList <>();
19171922 if (form .getAssayId () != null )
19181923 {
1919- protocols .add (ExperimentService .get ().getExpProtocol (form .getAssayId ()));
1920- ap = AssayService .get ().getProvider (protocols .get (0 ));
1924+ ExpProtocol protocol = ExperimentService .get ().getExpProtocol (form .getAssayId ());
1925+ // getExpProtocol() is unscoped, so verify the protocol is in scope before echoing its metadata; otherwise a user
1926+ // could enumerate arbitrary row ids and harvest assay names and container paths from folders they cannot read.
1927+ if (protocol == null || !AssayService .get ().getAssayProtocols (getContainer ()).contains (protocol ))
1928+ {
1929+ errors .reject (ERROR_MSG , "Unknown assay: " + form .getAssayId ());
1930+ return null ;
1931+ }
1932+ protocols .add (protocol );
1933+ ap = AssayService .get ().getProvider (protocol );
19211934 }
19221935 else if (form .getAssayType () != null )
19231936 {
0 commit comments