summaryrefslogtreecommitdiff
path: root/t/04-template-handling.t
blob: 04048b10e04eb6de00a1a39dec9617f9e05d17ea (plain)
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. $ENV{TMPDIR} = 't/var';
  5. use Test::More 'no_plan';
  6. use Test::Trap qw(trap $trap);
  7. use Test::Exception;
  8. use Error qw(:try);
  9. use LedgerSMB::AM;
  10. use LedgerSMB::Form;
  11. use LedgerSMB::Sysconfig;
  12. use LedgerSMB::Locale;
  13. use LedgerSMB::Template;
  14. use LedgerSMB::Template::HTML;
  15. $LedgerSMB::Sysconfig::tempdir = 't/var';
  16. my @r;
  17. my $temp;
  18. my $form;
  19. my $myconfig;
  20. my $template;
  21. my $FH;
  22. my $locale;
  23. $locale = LedgerSMB::Locale->get_handle('fr');
  24. # AM->check_template_name checks
  25. # check_template operates by calling $form->error if the checks fail
  26. $form = new Form;
  27. $myconfig = {'templates' => 'test'};
  28. for my $ext ('css', 'tex', 'txt', 'html', 'xml') {
  29. $form->{file} = "test/apples.${ext}";
  30. @r = trap{AM->check_template_name($myconfig, $form)};
  31. ok(!defined $trap->die,
  32. "AM, check_template_name: Template directory, ${ext}");
  33. }
  34. $form->{file} = 'css/apples.txt';
  35. @r = trap{AM->check_template_name($myconfig, $form)};
  36. ok(!defined $trap->die,
  37. 'AM, check_template_name: CSS directory, txt');
  38. $form->{file} = 'test2/apples.txt';
  39. @r = trap{AM->check_template_name($myconfig, $form)};
  40. is($trap->die, "Error: Not in a whitelisted directory: test2/apples.txt\n",
  41. 'AM, check_template_name: Invalid directory, non-css denial');
  42. $form->{file} = 'test/apples.exe';
  43. @r = trap{AM->check_template_name($myconfig, $form)};
  44. is($trap->die, "Error: Error: File is of type that is not allowed.\n",
  45. 'AM, check_template_name: Disallowed type denial');
  46. # adjusting backuppath to avoid triggering directory traversal detection
  47. $temp = ${LedgerSMB::Sysconfig::backuppath};
  48. ${LedgerSMB::Sysconfig::backuppath} = "foo";
  49. $form->{file} = "${LedgerSMB::Sysconfig::backuppath}/apples.txt";
  50. @r = trap{AM->check_template_name($myconfig, $form)};
  51. is($trap->die, "Error: Not allowed to access foo/ with this method\n",
  52. 'AM, check_template_name: Backup path denial');
  53. ${LedgerSMB::Sysconfig::backuppath} = $temp;
  54. $form->{file} = "css/../apples.txt";
  55. @r = trap{AM->check_template_name($myconfig, $form)};
  56. is($trap->die, "Error: Directory transversal not allowed.\n",
  57. 'AM, check_template_name: Directory transversal denial 1');
  58. $form->{file} = "/tmp/apples.txt";
  59. @r = trap{AM->check_template_name($myconfig, $form)};
  60. is($trap->die, "Error: Directory transversal not allowed.\n",
  61. 'AM, check_template_name: Directory transversal denial 2');
  62. $form->{file} = "test/apples.txt:evil";
  63. @r = trap{AM->check_template_name($myconfig, $form)};
  64. is($trap->die, "Error: Directory transversal not allowed.\n",
  65. 'AM, check_template_name: Directory transversal denial 3');
  66. $form->{file} = "c:\\evil.txt";
  67. @r = trap{AM->check_template_name($myconfig, $form)};
  68. is($trap->die, "Error: Directory transversal not allowed.\n",
  69. 'AM, check_template_name: Directory transversal denial 4');
  70. # AM->load_template checks
  71. # load_template takes its file name from form
  72. $form = new Form;
  73. $myconfig = {'templates' => 't/data'};
  74. $form->{file} = 't/data/04-not-there.txt';
  75. @r = trap{AM->load_template($myconfig, $form)};
  76. is($trap->die, "Error: t/data/04-not-there.txt : No such file or directory\n",
  77. 'AM, load_template: Die on non-existent file');
  78. $form->{file} = 't/data/04-template.html';
  79. AM->load_template($myconfig, $form);
  80. is($form->{body}, "I am a template.\nLook at me <?lsmb login ?>.\n",
  81. 'AM, load_template: Read existing file');
  82. # AM->save_template checks
  83. $form = new Form;
  84. $myconfig = {'templates' => 't/var/not here'};
  85. $form->{body} = "I am a template.\nLook at me.\n";
  86. $form->{file} = "$myconfig->{templates}/test.txt";
  87. @r = trap{AM->save_template($myconfig, $form)};
  88. is($trap->die,
  89. "Error: t/var/not here/test.txt : No such file or directory\n",
  90. 'AM, save_template: Die on unwritable file');
  91. $myconfig = {'templates' => 't/var'};
  92. $form->{body} = "I am a template.\nLook at me.";
  93. $form->{file} = "$myconfig->{templates}/04-template-save-test-$$.txt";
  94. ok(!-e $form->{file}, 'AM, save_template: Environment clean');
  95. AM->save_template($myconfig, $form);
  96. ok(-e $form->{file}, 'AM, save_template: File created');
  97. open($FH, '<', $form->{file});
  98. @r = <$FH>;
  99. close($FH);
  100. chomp(@r);
  101. is(join("\n", @r), $form->{body}, 'AM, save_template: Good save');
  102. is(unlink($form->{file}), 1, 'AM, save_template: removing testfile');
  103. ok(!-e $form->{file}, 'AM, save_template: testfile removed');
  104. # LedgerSMB::Template::HTML checks
  105. is(LedgerSMB::Template::HTML::get_template('04-template'), '04-template.html',
  106. 'HTML, get_template: Returned correct template file name');
  107. is(LedgerSMB::Template::HTML::preprocess('04-template'), '04-template',
  108. 'HTML, preprocess: Returned simple string unchanged');
  109. is(LedgerSMB::Template::HTML::preprocess('14 > 12'), '14 &gt; 12',
  110. 'HTML, preprocess: Returned properly escaped string');
  111. is_deeply(LedgerSMB::Template::HTML::preprocess([0, 'apple', 'mango&durian']),
  112. [0, 'apple', 'mango&amp;durian'],
  113. 'HTML, preprocess: Returned properly escaped array ref contents');
  114. is_deeply(LedgerSMB::Template::HTML::preprocess({'fruit' => '&veggies',
  115. 'test' => 1}),
  116. {'fruit' => '&amp;veggies', 'test' => 1},
  117. 'HTML, preprocess: Returned properly escaped hash ref contents');
  118. is_deeply(LedgerSMB::Template::HTML::preprocess({'fruit' => '&veggies',
  119. 'test' => ['nest', 'bird', '0 < 15', 1]}),
  120. {'fruit' => '&amp;veggies', 'test' => ['nest', 'bird', '0 &lt; 15', 1]},
  121. 'HTML, preprocess: Returned properly escaped nested contents');
  122. is(LedgerSMB::Template::HTML::postprocess({outputfile => '04-template'}),
  123. '04-template.html', 'HTML, postprocess: Return output filename');
  124. # Template->new
  125. $myconfig = {'templates' => 't/data'};
  126. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => 'x/0')}
  127. qr/Invalid language/, 'Template, new: Invalid language caught 1';
  128. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '1\\2')}
  129. qr/Invalid language/, 'Template, new: Invalid language caught 2';
  130. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '1:2')}
  131. qr/Invalid language/, 'Template, new: Invalid language caught 3';
  132. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '..')}
  133. qr/Invalid language/, 'Template, new: Invalid language caught 4';
  134. throws_ok{new LedgerSMB::Template('user' => $myconfig, 'language' => '.svn')}
  135. qr/Invalid language/,
  136. 'Template, new: Invalid language caught 5';
  137. $template = undef;
  138. $template = new LedgerSMB::Template('user' => $myconfig, 'language' => 'de');
  139. ok(defined $template, 'Template, new: Object creation with valid language');
  140. isa_ok($template, 'LedgerSMB::Template',
  141. 'Template, new: Object creation with valid language');
  142. is($template->{include_path}, 't/data/de;t/data',
  143. 'Template, new: Object creation with valid language has good include_path');
  144. $template = undef;
  145. $template = new LedgerSMB::Template('user' => $myconfig, 'language' => 'de',
  146. 'path' => 't/data');
  147. ok(defined $template,
  148. 'Template, new: Object creation with valid language and path');
  149. isa_ok($template, 'LedgerSMB::Template',
  150. 'Template, new: Object creation with valid language and path');
  151. is($template->{include_path}, 't/data',
  152. 'Template, new: Object creation with valid path overrides language');
  153. $template = undef;
  154. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  155. 'template' => '04-template');
  156. ok(defined $template,
  157. 'Template, new: Object creation with format and template');
  158. isa_ok($template, 'LedgerSMB::Template',
  159. 'Template, new: Object creation with format and template');
  160. is($template->{include_path}, 't/data',
  161. 'Template, new: Object creation with format and template');
  162. is($template->render({'login' => 'foo&bar'}), 't/var/04-template-output.html',
  163. 'Template, render: Simple HTML template, default filename');
  164. ok(-e 't/var/04-template-output.html', 'Template, render (HTML): File created');
  165. open($FH, '<', 't/var/04-template-output.html');
  166. @r = <$FH>;
  167. close($FH);
  168. chomp(@r);
  169. is(join("\n", @r), "I am a template.\nLook at me foo&amp;bar.",
  170. 'Template, render (HTML): Simple HTML template, correct output');
  171. is(unlink('t/var/04-template-output.html'), 1,
  172. 'Template, render: removing testfile');
  173. ok(!-e 't/var/04-template-output.html',
  174. 'Template, render (HTML): testfile removed');
  175. $template = undef;
  176. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  177. 'template' => '04-template', 'locale' => $locale);
  178. ok(defined $template,
  179. 'Template, new: Object creation with locale');
  180. isa_ok($template, 'LedgerSMB::Template',
  181. 'Template, new: Object creation with locale');
  182. $template = undef;
  183. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'HTML',
  184. 'template' => '04-template-2');
  185. ok(defined $template,
  186. 'Template, new: Object creation with non-existent template');
  187. throws_ok{$template->render({'login' => 'foo'})} qr/not found/,
  188. 'Template, render: File not found caught';
  189. $template = undef;
  190. $template = new LedgerSMB::Template('user' => $myconfig, 'format' => 'TODO',
  191. 'template' => '04-template');
  192. ok(defined $template,
  193. 'Template, new: Object creation with non-existent format');
  194. throws_ok{$template->render({'login' => 'foo'})} qr/Can't locate/,
  195. 'Template, render: Invalid format caught';