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