fluid_cli 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -0
  3. data/dev.yml +5 -0
  4. data/exe/fluid +24 -0
  5. data/lib/fluid_cli/api.rb +135 -0
  6. data/lib/fluid_cli/assets/post_auth_page/index.html.erb +34 -0
  7. data/lib/fluid_cli/assets/post_auth_page/style.css +58 -0
  8. data/lib/fluid_cli/command.rb +55 -0
  9. data/lib/fluid_cli/commands/help.rb +21 -0
  10. data/lib/fluid_cli/commands/login.rb +30 -0
  11. data/lib/fluid_cli/commands/logout.rb +38 -0
  12. data/lib/fluid_cli/commands/switch.rb +23 -0
  13. data/lib/fluid_cli/commands/theme/common/company_helper.rb +15 -0
  14. data/lib/fluid_cli/commands/theme/common/root_helper.rb +95 -0
  15. data/lib/fluid_cli/commands/theme/dev.rb +61 -0
  16. data/lib/fluid_cli/commands/theme/help.rb +21 -0
  17. data/lib/fluid_cli/commands/theme/init.rb +46 -0
  18. data/lib/fluid_cli/commands/theme/pull.rb +68 -0
  19. data/lib/fluid_cli/commands/theme/push.rb +132 -0
  20. data/lib/fluid_cli/commands/theme.rb +23 -0
  21. data/lib/fluid_cli/commands/whoami.rb +23 -0
  22. data/lib/fluid_cli/commands.rb +19 -0
  23. data/lib/fluid_cli/company_switcher.rb +69 -0
  24. data/lib/fluid_cli/context.rb +691 -0
  25. data/lib/fluid_cli/db.rb +114 -0
  26. data/lib/fluid_cli/entry_point.rb +10 -0
  27. data/lib/fluid_cli/environment.rb +32 -0
  28. data/lib/fluid_cli/file_system_listener.rb +29 -0
  29. data/lib/fluid_cli/form.rb +42 -0
  30. data/lib/fluid_cli/git.rb +319 -0
  31. data/lib/fluid_cli/http_request.rb +54 -0
  32. data/lib/fluid_cli/identity_auth/servlet.rb +39 -0
  33. data/lib/fluid_cli/identity_auth.rb +126 -0
  34. data/lib/fluid_cli/options.rb +38 -0
  35. data/lib/fluid_cli/theme/dev_server/certificate_manager.rb +79 -0
  36. data/lib/fluid_cli/theme/dev_server/errors.rb +9 -0
  37. data/lib/fluid_cli/theme/dev_server/header_hash.rb +98 -0
  38. data/lib/fluid_cli/theme/dev_server/hooks/file_change_hook.rb +39 -0
  39. data/lib/fluid_cli/theme/dev_server/hot_reload/resources/hot-reload-no-script.html +27 -0
  40. data/lib/fluid_cli/theme/dev_server/hot_reload/resources/hot_reload.js +28 -0
  41. data/lib/fluid_cli/theme/dev_server/hot_reload/resources/sse_client.js +43 -0
  42. data/lib/fluid_cli/theme/dev_server/hot_reload/resources/theme.js +16 -0
  43. data/lib/fluid_cli/theme/dev_server/hot_reload/script_injector.rb +54 -0
  44. data/lib/fluid_cli/theme/dev_server/hot_reload.rb +75 -0
  45. data/lib/fluid_cli/theme/dev_server/local_assets.rb +92 -0
  46. data/lib/fluid_cli/theme/dev_server/proxy.rb +235 -0
  47. data/lib/fluid_cli/theme/dev_server/proxy_param_builder.rb +82 -0
  48. data/lib/fluid_cli/theme/dev_server/reload_mode.rb +34 -0
  49. data/lib/fluid_cli/theme/dev_server/sse.rb +75 -0
  50. data/lib/fluid_cli/theme/dev_server/watcher.rb +57 -0
  51. data/lib/fluid_cli/theme/dev_server/web_server.rb +140 -0
  52. data/lib/fluid_cli/theme/dev_server.rb +289 -0
  53. data/lib/fluid_cli/theme/development_theme.rb +101 -0
  54. data/lib/fluid_cli/theme/file.rb +105 -0
  55. data/lib/fluid_cli/theme/forms/select.rb +33 -0
  56. data/lib/fluid_cli/theme/mime_type.rb +34 -0
  57. data/lib/fluid_cli/theme/presenters/theme_presenter.rb +49 -0
  58. data/lib/fluid_cli/theme/presenters/themes_presenter.rb +31 -0
  59. data/lib/fluid_cli/theme/root.rb +62 -0
  60. data/lib/fluid_cli/theme/syncer/checksums.rb +66 -0
  61. data/lib/fluid_cli/theme/syncer/downloader.rb +54 -0
  62. data/lib/fluid_cli/theme/syncer/error_reporter.rb +45 -0
  63. data/lib/fluid_cli/theme/syncer/merger.rb +53 -0
  64. data/lib/fluid_cli/theme/syncer/operation.rb +58 -0
  65. data/lib/fluid_cli/theme/syncer/standard_reporter.rb +32 -0
  66. data/lib/fluid_cli/theme/syncer/unsupported_script_warning.rb +90 -0
  67. data/lib/fluid_cli/theme/syncer/uploader/forms/apply_to_all.rb +41 -0
  68. data/lib/fluid_cli/theme/syncer/uploader/forms/apply_to_all_form.rb +37 -0
  69. data/lib/fluid_cli/theme/syncer/uploader/forms/base_strategy_form.rb +64 -0
  70. data/lib/fluid_cli/theme/syncer/uploader/forms/select_delete_strategy.rb +29 -0
  71. data/lib/fluid_cli/theme/syncer/uploader/forms/select_update_strategy.rb +30 -0
  72. data/lib/fluid_cli/theme/syncer/uploader/json_delete_handler.rb +49 -0
  73. data/lib/fluid_cli/theme/syncer/uploader/json_update_handler.rb +71 -0
  74. data/lib/fluid_cli/theme/syncer/uploader.rb +105 -0
  75. data/lib/fluid_cli/theme/syncer.rb +412 -0
  76. data/lib/fluid_cli/theme/theme.rb +186 -0
  77. data/lib/fluid_cli/theme/ui/sync_progress_bar.rb +22 -0
  78. data/lib/fluid_cli/thread_pool/job.rb +35 -0
  79. data/lib/fluid_cli/thread_pool.rb +49 -0
  80. data/lib/fluid_cli/version.rb +3 -0
  81. data/lib/fluid_cli.rb +59 -0
  82. data/vendor/deps/base64/.document +5 -0
  83. data/vendor/deps/base64/.gitignore +9 -0
  84. data/vendor/deps/base64/BSDL +22 -0
  85. data/vendor/deps/base64/COPYING +56 -0
  86. data/vendor/deps/base64/Gemfile +9 -0
  87. data/vendor/deps/base64/LEGAL +60 -0
  88. data/vendor/deps/base64/README.md +48 -0
  89. data/vendor/deps/base64/Rakefile +31 -0
  90. data/vendor/deps/base64/base64.gemspec +28 -0
  91. data/vendor/deps/base64/bin/console +14 -0
  92. data/vendor/deps/base64/bin/setup +8 -0
  93. data/vendor/deps/base64/lib/base64.rb +382 -0
  94. data/vendor/deps/base64/sig/base64.rbs +358 -0
  95. data/vendor/deps/base64/test/base64/test_base64.rb +115 -0
  96. data/vendor/deps/base64/test_sig/test_base64.rb +44 -0
  97. data/vendor/deps/cli-kit/REVISION +1 -0
  98. data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +286 -0
  99. data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +215 -0
  100. data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +128 -0
  101. data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +125 -0
  102. data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +130 -0
  103. data/vendor/deps/cli-kit/lib/cli/kit/args.rb +16 -0
  104. data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +30 -0
  105. data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +268 -0
  106. data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +150 -0
  107. data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
  108. data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +28 -0
  109. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +166 -0
  110. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +92 -0
  111. data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +91 -0
  112. data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +92 -0
  113. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +94 -0
  114. data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +248 -0
  115. data/vendor/deps/cli-kit/lib/cli/kit/parse_args.rb +55 -0
  116. data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +66 -0
  117. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +260 -0
  118. data/vendor/deps/cli-kit/lib/cli/kit/support.rb +11 -0
  119. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +290 -0
  120. data/vendor/deps/cli-kit/lib/cli/kit/util.rb +118 -0
  121. data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
  122. data/vendor/deps/cli-kit/lib/cli/kit.rb +139 -0
  123. data/vendor/deps/cli-ui/REVISION +1 -0
  124. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +218 -0
  125. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +101 -0
  126. data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +219 -0
  127. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +67 -0
  128. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +179 -0
  129. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +152 -0
  130. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +127 -0
  131. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +286 -0
  132. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
  133. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
  134. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +64 -0
  135. data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +132 -0
  136. data/vendor/deps/cli-ui/lib/cli/ui/progress_reporter.rb +209 -0
  137. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +583 -0
  138. data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
  139. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +381 -0
  140. data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +48 -0
  141. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +602 -0
  142. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +79 -0
  143. data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +399 -0
  144. data/vendor/deps/cli-ui/lib/cli/ui/table.rb +83 -0
  145. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +55 -0
  146. data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +106 -0
  147. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +8 -0
  148. data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +46 -0
  149. data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +79 -0
  150. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +89 -0
  151. data/vendor/deps/cli-ui/lib/cli/ui/work_queue.rb +142 -0
  152. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +61 -0
  153. data/vendor/deps/cli-ui/lib/cli/ui.rb +359 -0
  154. data/vendor/deps/cli-ui/vendor/reentrant_mutex.rb +78 -0
  155. data/vendor/deps/debug/CONTRIBUTING.md +573 -0
  156. data/vendor/deps/debug/Gemfile +10 -0
  157. data/vendor/deps/debug/LICENSE.txt +22 -0
  158. data/vendor/deps/debug/README.md +996 -0
  159. data/vendor/deps/debug/Rakefile +57 -0
  160. data/vendor/deps/debug/TODO.md +23 -0
  161. data/vendor/deps/debug/debug.gemspec +33 -0
  162. data/vendor/deps/debug/exe/rdbg +53 -0
  163. data/vendor/deps/debug/ext/debug/Makefile +273 -0
  164. data/vendor/deps/debug/ext/debug/debug.c +228 -0
  165. data/vendor/deps/debug/ext/debug/debug_version.h +1 -0
  166. data/vendor/deps/debug/ext/debug/extconf.rb +27 -0
  167. data/vendor/deps/debug/ext/debug/iseq_collector.c +93 -0
  168. data/vendor/deps/debug/lib/debug/abbrev_command.rb +77 -0
  169. data/vendor/deps/debug/lib/debug/breakpoint.rb +556 -0
  170. data/vendor/deps/debug/lib/debug/client.rb +263 -0
  171. data/vendor/deps/debug/lib/debug/color.rb +123 -0
  172. data/vendor/deps/debug/lib/debug/config.rb +592 -0
  173. data/vendor/deps/debug/lib/debug/console.rb +224 -0
  174. data/vendor/deps/debug/lib/debug/dap_custom/traceInspector.rb +336 -0
  175. data/vendor/deps/debug/lib/debug/debug.bundle +0 -0
  176. data/vendor/deps/debug/lib/debug/frame_info.rb +190 -0
  177. data/vendor/deps/debug/lib/debug/irb_integration.rb +37 -0
  178. data/vendor/deps/debug/lib/debug/local.rb +115 -0
  179. data/vendor/deps/debug/lib/debug/open.rb +13 -0
  180. data/vendor/deps/debug/lib/debug/open_nonstop.rb +15 -0
  181. data/vendor/deps/debug/lib/debug/prelude.rb +50 -0
  182. data/vendor/deps/debug/lib/debug/server.rb +534 -0
  183. data/vendor/deps/debug/lib/debug/server_cdp.rb +1348 -0
  184. data/vendor/deps/debug/lib/debug/server_dap.rb +1108 -0
  185. data/vendor/deps/debug/lib/debug/session.rb +2667 -0
  186. data/vendor/deps/debug/lib/debug/source_repository.rb +150 -0
  187. data/vendor/deps/debug/lib/debug/start.rb +5 -0
  188. data/vendor/deps/debug/lib/debug/thread_client.rb +1457 -0
  189. data/vendor/deps/debug/lib/debug/tracer.rb +241 -0
  190. data/vendor/deps/debug/lib/debug/version.rb +5 -0
  191. data/vendor/deps/debug/lib/debug.rb +9 -0
  192. data/vendor/deps/debug/misc/README.md.erb +660 -0
  193. data/vendor/deps/listen/.github/release-drafter.yml +17 -0
  194. data/vendor/deps/listen/.github/workflows/development.yml +67 -0
  195. data/vendor/deps/listen/.github/workflows/push.yml +12 -0
  196. data/vendor/deps/listen/.gitignore +28 -0
  197. data/vendor/deps/listen/.rspec +3 -0
  198. data/vendor/deps/listen/.rubocop.yml +283 -0
  199. data/vendor/deps/listen/.yardopts +11 -0
  200. data/vendor/deps/listen/CHANGELOG.md +1 -0
  201. data/vendor/deps/listen/CONTRIBUTING.md +45 -0
  202. data/vendor/deps/listen/Gemfile +33 -0
  203. data/vendor/deps/listen/Guardfile +26 -0
  204. data/vendor/deps/listen/LICENSE.txt +22 -0
  205. data/vendor/deps/listen/README.md +490 -0
  206. data/vendor/deps/listen/Rakefile +154 -0
  207. data/vendor/deps/listen/bin/listen +11 -0
  208. data/vendor/deps/listen/lib/listen/adapter/base.rb +129 -0
  209. data/vendor/deps/listen/lib/listen/adapter/bsd.rb +104 -0
  210. data/vendor/deps/listen/lib/listen/adapter/config.rb +31 -0
  211. data/vendor/deps/listen/lib/listen/adapter/darwin.rb +77 -0
  212. data/vendor/deps/listen/lib/listen/adapter/linux.rb +108 -0
  213. data/vendor/deps/listen/lib/listen/adapter/polling.rb +40 -0
  214. data/vendor/deps/listen/lib/listen/adapter/windows.rb +96 -0
  215. data/vendor/deps/listen/lib/listen/adapter.rb +43 -0
  216. data/vendor/deps/listen/lib/listen/backend.rb +40 -0
  217. data/vendor/deps/listen/lib/listen/change.rb +69 -0
  218. data/vendor/deps/listen/lib/listen/cli.rb +65 -0
  219. data/vendor/deps/listen/lib/listen/directory.rb +93 -0
  220. data/vendor/deps/listen/lib/listen/error.rb +11 -0
  221. data/vendor/deps/listen/lib/listen/event/config.rb +39 -0
  222. data/vendor/deps/listen/lib/listen/event/loop.rb +92 -0
  223. data/vendor/deps/listen/lib/listen/event/processor.rb +128 -0
  224. data/vendor/deps/listen/lib/listen/event/queue.rb +52 -0
  225. data/vendor/deps/listen/lib/listen/file.rb +95 -0
  226. data/vendor/deps/listen/lib/listen/fsm.rb +131 -0
  227. data/vendor/deps/listen/lib/listen/listener/config.rb +41 -0
  228. data/vendor/deps/listen/lib/listen/listener.rb +136 -0
  229. data/vendor/deps/listen/lib/listen/logger.rb +65 -0
  230. data/vendor/deps/listen/lib/listen/monotonic_time.rb +27 -0
  231. data/vendor/deps/listen/lib/listen/options.rb +24 -0
  232. data/vendor/deps/listen/lib/listen/queue_optimizer.rb +129 -0
  233. data/vendor/deps/listen/lib/listen/record/entry.rb +66 -0
  234. data/vendor/deps/listen/lib/listen/record/symlink_detector.rb +47 -0
  235. data/vendor/deps/listen/lib/listen/record.rb +122 -0
  236. data/vendor/deps/listen/lib/listen/silencer/controller.rb +50 -0
  237. data/vendor/deps/listen/lib/listen/silencer.rb +106 -0
  238. data/vendor/deps/listen/lib/listen/thread.rb +54 -0
  239. data/vendor/deps/listen/lib/listen/version.rb +5 -0
  240. data/vendor/deps/listen/lib/listen.rb +47 -0
  241. data/vendor/deps/listen/listen.gemspec +40 -0
  242. data/vendor/deps/listen/spec/acceptance/listen_spec.rb +320 -0
  243. data/vendor/deps/listen/spec/lib/listen/adapter/base_spec.rb +101 -0
  244. data/vendor/deps/listen/spec/lib/listen/adapter/bsd_spec.rb +13 -0
  245. data/vendor/deps/listen/spec/lib/listen/adapter/config_spec.rb +122 -0
  246. data/vendor/deps/listen/spec/lib/listen/adapter/darwin_spec.rb +82 -0
  247. data/vendor/deps/listen/spec/lib/listen/adapter/linux_spec.rb +199 -0
  248. data/vendor/deps/listen/spec/lib/listen/adapter/polling_spec.rb +83 -0
  249. data/vendor/deps/listen/spec/lib/listen/adapter/windows_spec.rb +13 -0
  250. data/vendor/deps/listen/spec/lib/listen/adapter_spec.rb +69 -0
  251. data/vendor/deps/listen/spec/lib/listen/backend_spec.rb +82 -0
  252. data/vendor/deps/listen/spec/lib/listen/change_spec.rb +102 -0
  253. data/vendor/deps/listen/spec/lib/listen/cli_spec.rb +116 -0
  254. data/vendor/deps/listen/spec/lib/listen/directory_spec.rb +284 -0
  255. data/vendor/deps/listen/spec/lib/listen/event/config_spec.rb +33 -0
  256. data/vendor/deps/listen/spec/lib/listen/event/loop_spec.rb +118 -0
  257. data/vendor/deps/listen/spec/lib/listen/event/processor_spec.rb +250 -0
  258. data/vendor/deps/listen/spec/lib/listen/event/queue_spec.rb +118 -0
  259. data/vendor/deps/listen/spec/lib/listen/file_spec.rb +254 -0
  260. data/vendor/deps/listen/spec/lib/listen/fsm_spec.rb +147 -0
  261. data/vendor/deps/listen/spec/lib/listen/listener/config_spec.rb +29 -0
  262. data/vendor/deps/listen/spec/lib/listen/listener_spec.rb +321 -0
  263. data/vendor/deps/listen/spec/lib/listen/logger_spec.rb +212 -0
  264. data/vendor/deps/listen/spec/lib/listen/monotonic_time_spec.rb +58 -0
  265. data/vendor/deps/listen/spec/lib/listen/queue_optimizer_spec.rb +111 -0
  266. data/vendor/deps/listen/spec/lib/listen/record_spec.rb +424 -0
  267. data/vendor/deps/listen/spec/lib/listen/silencer/controller_spec.rb +97 -0
  268. data/vendor/deps/listen/spec/lib/listen/silencer_spec.rb +109 -0
  269. data/vendor/deps/listen/spec/lib/listen/thread_spec.rb +133 -0
  270. data/vendor/deps/listen/spec/lib/listen_spec.rb +25 -0
  271. data/vendor/deps/listen/spec/spec_helper.rb +49 -0
  272. data/vendor/deps/listen/spec/support/acceptance_helper.rb +260 -0
  273. data/vendor/deps/listen/spec/support/fixtures_helper.rb +32 -0
  274. data/vendor/deps/listen/spec/support/platform_helper.rb +17 -0
  275. data/vendor/deps/observer/.github/dependabot.yml +6 -0
  276. data/vendor/deps/observer/.github/workflows/test.yml +33 -0
  277. data/vendor/deps/observer/.gitignore +8 -0
  278. data/vendor/deps/observer/BSDL +22 -0
  279. data/vendor/deps/observer/COPYING +56 -0
  280. data/vendor/deps/observer/Gemfile +9 -0
  281. data/vendor/deps/observer/README.md +139 -0
  282. data/vendor/deps/observer/Rakefile +10 -0
  283. data/vendor/deps/observer/bin/console +14 -0
  284. data/vendor/deps/observer/bin/setup +8 -0
  285. data/vendor/deps/observer/lib/observer.rb +229 -0
  286. data/vendor/deps/observer/observer.gemspec +32 -0
  287. data/vendor/deps/observer/test/test_observer.rb +66 -0
  288. data/vendor/deps/webrick/.gitignore +9 -0
  289. data/vendor/deps/webrick/Gemfile +3 -0
  290. data/vendor/deps/webrick/LICENSE.txt +22 -0
  291. data/vendor/deps/webrick/README.md +61 -0
  292. data/vendor/deps/webrick/Rakefile +10 -0
  293. data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
  294. data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
  295. data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
  296. data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
  297. data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
  298. data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
  299. data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
  300. data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
  301. data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
  302. data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
  303. data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
  304. data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
  305. data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
  306. data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
  307. data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
  308. data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
  309. data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
  310. data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
  311. data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
  312. data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
  313. data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  314. data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
  315. data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
  316. data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
  317. data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
  318. data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
  319. data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
  320. data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
  321. data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
  322. data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
  323. data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
  324. data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
  325. data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
  326. data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
  327. data/vendor/deps/webrick/lib/webrick.rb +232 -0
  328. data/vendor/deps/webrick/webrick.gemspec +74 -0
  329. metadata +412 -0
@@ -0,0 +1,395 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # httpauth/digestauth.rb -- HTTP digest access authentication
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2003 Internet Programming with Ruby writers.
7
+ # Copyright (c) 2003 H.M.
8
+ #
9
+ # The original implementation is provided by H.M.
10
+ # URL: http://rwiki.jin.gr.jp/cgi-bin/rw-cgi.rb?cmd=view;name=
11
+ # %C7%A7%BE%DA%B5%A1%C7%BD%A4%F2%B2%FE%C2%A4%A4%B7%A4%C6%A4%DF%A4%EB
12
+ #
13
+ # $IPR: digestauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $
14
+
15
+ require_relative '../config'
16
+ require_relative '../httpstatus'
17
+ require_relative 'authenticator'
18
+ require 'digest/md5'
19
+ require 'digest/sha1'
20
+
21
+ module WEBrick
22
+ module HTTPAuth
23
+
24
+ ##
25
+ # RFC 2617 Digest Access Authentication for WEBrick
26
+ #
27
+ # Use this class to add digest authentication to a WEBrick servlet.
28
+ #
29
+ # Here is an example of how to set up DigestAuth:
30
+ #
31
+ # config = { :Realm => 'DigestAuth example realm' }
32
+ #
33
+ # htdigest = WEBrick::HTTPAuth::Htdigest.new 'my_password_file'
34
+ # htdigest.set_passwd config[:Realm], 'username', 'password'
35
+ # htdigest.flush
36
+ #
37
+ # config[:UserDB] = htdigest
38
+ #
39
+ # digest_auth = WEBrick::HTTPAuth::DigestAuth.new config
40
+ #
41
+ # When using this as with a servlet be sure not to create a new DigestAuth
42
+ # object in the servlet's #initialize. By default WEBrick creates a new
43
+ # servlet instance for every request and the DigestAuth object must be
44
+ # used across requests.
45
+
46
+ class DigestAuth
47
+ include Authenticator
48
+
49
+ AuthScheme = "Digest" # :nodoc:
50
+
51
+ ##
52
+ # Struct containing the opaque portion of the digest authentication
53
+
54
+ OpaqueInfo = Struct.new(:time, :nonce, :nc) # :nodoc:
55
+
56
+ ##
57
+ # Digest authentication algorithm
58
+
59
+ attr_reader :algorithm
60
+
61
+ ##
62
+ # Quality of protection. RFC 2617 defines "auth" and "auth-int"
63
+
64
+ attr_reader :qop
65
+
66
+ ##
67
+ # Used by UserDB to create a digest password entry
68
+
69
+ def self.make_passwd(realm, user, pass)
70
+ pass ||= ""
71
+ Digest::MD5::hexdigest([user, realm, pass].join(":"))
72
+ end
73
+
74
+ ##
75
+ # Creates a new DigestAuth instance. Be sure to use the same DigestAuth
76
+ # instance for multiple requests as it saves state between requests in
77
+ # order to perform authentication.
78
+ #
79
+ # See WEBrick::Config::DigestAuth for default configuration entries
80
+ #
81
+ # You must supply the following configuration entries:
82
+ #
83
+ # :Realm:: The name of the realm being protected.
84
+ # :UserDB:: A database of usernames and passwords.
85
+ # A WEBrick::HTTPAuth::Htdigest instance should be used.
86
+
87
+ def initialize(config, default=Config::DigestAuth)
88
+ check_init(config)
89
+ @config = default.dup.update(config)
90
+ @algorithm = @config[:Algorithm]
91
+ @domain = @config[:Domain]
92
+ @qop = @config[:Qop]
93
+ @use_opaque = @config[:UseOpaque]
94
+ @use_next_nonce = @config[:UseNextNonce]
95
+ @check_nc = @config[:CheckNc]
96
+ @use_auth_info_header = @config[:UseAuthenticationInfoHeader]
97
+ @nonce_expire_period = @config[:NonceExpirePeriod]
98
+ @nonce_expire_delta = @config[:NonceExpireDelta]
99
+ @internet_explorer_hack = @config[:InternetExplorerHack]
100
+
101
+ case @algorithm
102
+ when 'MD5','MD5-sess'
103
+ @h = Digest::MD5
104
+ when 'SHA1','SHA1-sess' # it is a bonus feature :-)
105
+ @h = Digest::SHA1
106
+ else
107
+ msg = format('Algorithm "%s" is not supported.', @algorithm)
108
+ raise ArgumentError.new(msg)
109
+ end
110
+
111
+ @instance_key = hexdigest(self.__id__, Time.now.to_i, Process.pid)
112
+ @opaques = {}
113
+ @last_nonce_expire = Time.now
114
+ @mutex = Thread::Mutex.new
115
+ end
116
+
117
+ ##
118
+ # Authenticates a +req+ and returns a 401 Unauthorized using +res+ if
119
+ # the authentication was not correct.
120
+
121
+ def authenticate(req, res)
122
+ unless result = @mutex.synchronize{ _authenticate(req, res) }
123
+ challenge(req, res)
124
+ end
125
+ if result == :nonce_is_stale
126
+ challenge(req, res, true)
127
+ end
128
+ return true
129
+ end
130
+
131
+ ##
132
+ # Returns a challenge response which asks for authentication information
133
+
134
+ def challenge(req, res, stale=false)
135
+ nonce = generate_next_nonce(req)
136
+ if @use_opaque
137
+ opaque = generate_opaque(req)
138
+ @opaques[opaque].nonce = nonce
139
+ end
140
+
141
+ param = Hash.new
142
+ param["realm"] = HTTPUtils::quote(@realm)
143
+ param["domain"] = HTTPUtils::quote(@domain.to_a.join(" ")) if @domain
144
+ param["nonce"] = HTTPUtils::quote(nonce)
145
+ param["opaque"] = HTTPUtils::quote(opaque) if opaque
146
+ param["stale"] = stale.to_s
147
+ param["algorithm"] = @algorithm
148
+ param["qop"] = HTTPUtils::quote(@qop.to_a.join(",")) if @qop
149
+
150
+ res[@response_field] =
151
+ "#{@auth_scheme} " + param.map{|k,v| "#{k}=#{v}" }.join(", ")
152
+ info("%s: %s", @response_field, res[@response_field]) if $DEBUG
153
+ raise @auth_exception
154
+ end
155
+
156
+ private
157
+
158
+ # :stopdoc:
159
+
160
+ MustParams = ['username','realm','nonce','uri','response']
161
+ MustParamsAuth = ['cnonce','nc']
162
+
163
+ def _authenticate(req, res)
164
+ unless digest_credentials = check_scheme(req)
165
+ return false
166
+ end
167
+
168
+ auth_req = split_param_value(digest_credentials)
169
+ if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
170
+ req_params = MustParams + MustParamsAuth
171
+ else
172
+ req_params = MustParams
173
+ end
174
+ req_params.each{|key|
175
+ unless auth_req.has_key?(key)
176
+ error('%s: parameter missing. "%s"', auth_req['username'], key)
177
+ raise HTTPStatus::BadRequest
178
+ end
179
+ }
180
+
181
+ if !check_uri(req, auth_req)
182
+ raise HTTPStatus::BadRequest
183
+ end
184
+
185
+ if auth_req['realm'] != @realm
186
+ error('%s: realm unmatch. "%s" for "%s"',
187
+ auth_req['username'], auth_req['realm'], @realm)
188
+ return false
189
+ end
190
+
191
+ auth_req['algorithm'] ||= 'MD5'
192
+ if auth_req['algorithm'].upcase != @algorithm.upcase
193
+ error('%s: algorithm unmatch. "%s" for "%s"',
194
+ auth_req['username'], auth_req['algorithm'], @algorithm)
195
+ return false
196
+ end
197
+
198
+ if (@qop.nil? && auth_req.has_key?('qop')) ||
199
+ (@qop && (! @qop.member?(auth_req['qop'])))
200
+ error('%s: the qop is not allowed. "%s"',
201
+ auth_req['username'], auth_req['qop'])
202
+ return false
203
+ end
204
+
205
+ password = @userdb.get_passwd(@realm, auth_req['username'], @reload_db)
206
+ unless password
207
+ error('%s: the user is not allowed.', auth_req['username'])
208
+ return false
209
+ end
210
+
211
+ nonce_is_invalid = false
212
+ if @use_opaque
213
+ info("@opaque = %s", @opaque.inspect) if $DEBUG
214
+ if !(opaque = auth_req['opaque'])
215
+ error('%s: opaque is not given.', auth_req['username'])
216
+ nonce_is_invalid = true
217
+ elsif !(opaque_struct = @opaques[opaque])
218
+ error('%s: invalid opaque is given.', auth_req['username'])
219
+ nonce_is_invalid = true
220
+ elsif !check_opaque(opaque_struct, req, auth_req)
221
+ @opaques.delete(auth_req['opaque'])
222
+ nonce_is_invalid = true
223
+ end
224
+ elsif !check_nonce(req, auth_req)
225
+ nonce_is_invalid = true
226
+ end
227
+
228
+ if /-sess$/i =~ auth_req['algorithm']
229
+ ha1 = hexdigest(password, auth_req['nonce'], auth_req['cnonce'])
230
+ else
231
+ ha1 = password
232
+ end
233
+
234
+ if auth_req['qop'] == "auth" || auth_req['qop'] == nil
235
+ ha2 = hexdigest(req.request_method, auth_req['uri'])
236
+ ha2_res = hexdigest("", auth_req['uri'])
237
+ elsif auth_req['qop'] == "auth-int"
238
+ body_digest = @h.new
239
+ req.body { |chunk| body_digest.update(chunk) }
240
+ body_digest = body_digest.hexdigest
241
+ ha2 = hexdigest(req.request_method, auth_req['uri'], body_digest)
242
+ ha2_res = hexdigest("", auth_req['uri'], body_digest)
243
+ end
244
+
245
+ if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
246
+ param2 = ['nonce', 'nc', 'cnonce', 'qop'].map{|key|
247
+ auth_req[key]
248
+ }.join(':')
249
+ digest = hexdigest(ha1, param2, ha2)
250
+ digest_res = hexdigest(ha1, param2, ha2_res)
251
+ else
252
+ digest = hexdigest(ha1, auth_req['nonce'], ha2)
253
+ digest_res = hexdigest(ha1, auth_req['nonce'], ha2_res)
254
+ end
255
+
256
+ if digest != auth_req['response']
257
+ error("%s: digest unmatch.", auth_req['username'])
258
+ return false
259
+ elsif nonce_is_invalid
260
+ error('%s: digest is valid, but nonce is not valid.',
261
+ auth_req['username'])
262
+ return :nonce_is_stale
263
+ elsif @use_auth_info_header
264
+ auth_info = {
265
+ 'nextnonce' => generate_next_nonce(req),
266
+ 'rspauth' => digest_res
267
+ }
268
+ if @use_opaque
269
+ opaque_struct.time = req.request_time
270
+ opaque_struct.nonce = auth_info['nextnonce']
271
+ opaque_struct.nc = "%08x" % (auth_req['nc'].hex + 1)
272
+ end
273
+ if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
274
+ ['qop','cnonce','nc'].each{|key|
275
+ auth_info[key] = auth_req[key]
276
+ }
277
+ end
278
+ res[@resp_info_field] = auth_info.keys.map{|key|
279
+ if key == 'nc'
280
+ key + '=' + auth_info[key]
281
+ else
282
+ key + "=" + HTTPUtils::quote(auth_info[key])
283
+ end
284
+ }.join(', ')
285
+ end
286
+ info('%s: authentication succeeded.', auth_req['username'])
287
+ req.user = auth_req['username']
288
+ return true
289
+ end
290
+
291
+ def split_param_value(string)
292
+ ret = {}
293
+ string.scan(/\G\s*([\w\-.*%!]+)=\s*(?:\"((?>\\.|[^\"])*)\"|([^,\"]*))\s*,?/) do
294
+ ret[$1] = $3 || $2.gsub(/\\(.)/, "\\1")
295
+ end
296
+ ret
297
+ end
298
+
299
+ def generate_next_nonce(req)
300
+ now = "%012d" % req.request_time.to_i
301
+ pk = hexdigest(now, @instance_key)[0,32]
302
+ nonce = [now + ":" + pk].pack("m0") # it has 60 length of chars.
303
+ nonce
304
+ end
305
+
306
+ def check_nonce(req, auth_req)
307
+ username = auth_req['username']
308
+ nonce = auth_req['nonce']
309
+
310
+ pub_time, pk = nonce.unpack("m*")[0].split(":", 2)
311
+ if (!pub_time || !pk)
312
+ error("%s: empty nonce is given", username)
313
+ return false
314
+ elsif (hexdigest(pub_time, @instance_key)[0,32] != pk)
315
+ error("%s: invalid private-key: %s for %s",
316
+ username, hexdigest(pub_time, @instance_key)[0,32], pk)
317
+ return false
318
+ end
319
+
320
+ diff_time = req.request_time.to_i - pub_time.to_i
321
+ if (diff_time < 0)
322
+ error("%s: difference of time-stamp is negative.", username)
323
+ return false
324
+ elsif diff_time > @nonce_expire_period
325
+ error("%s: nonce is expired.", username)
326
+ return false
327
+ end
328
+
329
+ return true
330
+ end
331
+
332
+ def generate_opaque(req)
333
+ @mutex.synchronize{
334
+ now = req.request_time
335
+ if now - @last_nonce_expire > @nonce_expire_delta
336
+ @opaques.delete_if{|key,val|
337
+ (now - val.time) > @nonce_expire_period
338
+ }
339
+ @last_nonce_expire = now
340
+ end
341
+ begin
342
+ opaque = Utils::random_string(16)
343
+ end while @opaques[opaque]
344
+ @opaques[opaque] = OpaqueInfo.new(now, nil, '00000001')
345
+ opaque
346
+ }
347
+ end
348
+
349
+ def check_opaque(opaque_struct, req, auth_req)
350
+ if (@use_next_nonce && auth_req['nonce'] != opaque_struct.nonce)
351
+ error('%s: nonce unmatched. "%s" for "%s"',
352
+ auth_req['username'], auth_req['nonce'], opaque_struct.nonce)
353
+ return false
354
+ elsif !check_nonce(req, auth_req)
355
+ return false
356
+ end
357
+ if (@check_nc && auth_req['nc'] != opaque_struct.nc)
358
+ error('%s: nc unmatched."%s" for "%s"',
359
+ auth_req['username'], auth_req['nc'], opaque_struct.nc)
360
+ return false
361
+ end
362
+ true
363
+ end
364
+
365
+ def check_uri(req, auth_req)
366
+ uri = auth_req['uri']
367
+ if uri != req.request_uri.to_s && uri != req.unparsed_uri &&
368
+ (@internet_explorer_hack && uri != req.path)
369
+ error('%s: uri unmatch. "%s" for "%s"', auth_req['username'],
370
+ auth_req['uri'], req.request_uri.to_s)
371
+ return false
372
+ end
373
+ true
374
+ end
375
+
376
+ def hexdigest(*args)
377
+ @h.hexdigest(args.join(":"))
378
+ end
379
+
380
+ # :startdoc:
381
+ end
382
+
383
+ ##
384
+ # Digest authentication for proxy servers. See DigestAuth for details.
385
+
386
+ class ProxyDigestAuth < DigestAuth
387
+ include ProxyAuthenticator
388
+
389
+ private
390
+ def check_uri(req, auth_req) # :nodoc:
391
+ return true
392
+ end
393
+ end
394
+ end
395
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # httpauth/htdigest.rb -- Apache compatible htdigest file
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2003 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $
10
+
11
+ require_relative 'userdb'
12
+ require_relative 'digestauth'
13
+ require 'tempfile'
14
+
15
+ module WEBrick
16
+ module HTTPAuth
17
+
18
+ ##
19
+ # Htdigest accesses apache-compatible digest password files. Passwords are
20
+ # matched to a realm where they are valid. For security, the path for a
21
+ # digest password database should be stored outside of the paths available
22
+ # to the HTTP server.
23
+ #
24
+ # Htdigest is intended for use with WEBrick::HTTPAuth::DigestAuth and
25
+ # stores passwords using cryptographic hashes.
26
+ #
27
+ # htpasswd = WEBrick::HTTPAuth::Htdigest.new 'my_password_file'
28
+ # htpasswd.set_passwd 'my realm', 'username', 'password'
29
+ # htpasswd.flush
30
+
31
+ class Htdigest
32
+ include UserDB
33
+
34
+ ##
35
+ # Open a digest password database at +path+
36
+
37
+ def initialize(path)
38
+ @path = path
39
+ @mtime = Time.at(0)
40
+ @digest = Hash.new
41
+ @mutex = Thread::Mutex::new
42
+ @auth_type = DigestAuth
43
+ File.open(@path,"a").close unless File.exist?(@path)
44
+ reload
45
+ end
46
+
47
+ ##
48
+ # Reloads passwords from the database
49
+
50
+ def reload
51
+ mtime = File::mtime(@path)
52
+ if mtime > @mtime
53
+ @digest.clear
54
+ File.open(@path){|io|
55
+ while line = io.gets
56
+ line.chomp!
57
+ user, realm, pass = line.split(/:/, 3)
58
+ unless @digest[realm]
59
+ @digest[realm] = Hash.new
60
+ end
61
+ @digest[realm][user] = pass
62
+ end
63
+ }
64
+ @mtime = mtime
65
+ end
66
+ end
67
+
68
+ ##
69
+ # Flush the password database. If +output+ is given the database will
70
+ # be written there instead of to the original path.
71
+
72
+ def flush(output=nil)
73
+ output ||= @path
74
+ tmp = Tempfile.create("htpasswd", File::dirname(output))
75
+ renamed = false
76
+ begin
77
+ each{|item| tmp.puts(item.join(":")) }
78
+ tmp.close
79
+ File::rename(tmp.path, output)
80
+ renamed = true
81
+ ensure
82
+ tmp.close
83
+ File.unlink(tmp.path) if !renamed
84
+ end
85
+ end
86
+
87
+ ##
88
+ # Retrieves a password from the database for +user+ in +realm+. If
89
+ # +reload_db+ is true the database will be reloaded first.
90
+
91
+ def get_passwd(realm, user, reload_db)
92
+ reload() if reload_db
93
+ if hash = @digest[realm]
94
+ hash[user]
95
+ end
96
+ end
97
+
98
+ ##
99
+ # Sets a password in the database for +user+ in +realm+ to +pass+.
100
+
101
+ def set_passwd(realm, user, pass)
102
+ @mutex.synchronize{
103
+ unless @digest[realm]
104
+ @digest[realm] = Hash.new
105
+ end
106
+ @digest[realm][user] = make_passwd(realm, user, pass)
107
+ }
108
+ end
109
+
110
+ ##
111
+ # Removes a password from the database for +user+ in +realm+.
112
+
113
+ def delete_passwd(realm, user)
114
+ if hash = @digest[realm]
115
+ hash.delete(user)
116
+ end
117
+ end
118
+
119
+ ##
120
+ # Iterate passwords in the database.
121
+
122
+ def each # :yields: [user, realm, password_hash]
123
+ @digest.keys.sort.each{|realm|
124
+ hash = @digest[realm]
125
+ hash.keys.sort.each{|user|
126
+ yield([user, realm, hash[user]])
127
+ }
128
+ }
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # httpauth/htgroup.rb -- Apache compatible htgroup file
4
+ #
5
+ # Author: IPR -- Internet Programming with Ruby -- writers
6
+ # Copyright (c) 2003 Internet Programming with Ruby writers. All rights
7
+ # reserved.
8
+ #
9
+ # $IPR: htgroup.rb,v 1.1 2003/02/16 22:22:56 gotoyuzo Exp $
10
+
11
+ require 'tempfile'
12
+
13
+ module WEBrick
14
+ module HTTPAuth
15
+
16
+ ##
17
+ # Htgroup accesses apache-compatible group files. Htgroup can be used to
18
+ # provide group-based authentication for users. Currently Htgroup is not
19
+ # directly integrated with any authenticators in WEBrick. For security,
20
+ # the path for a digest password database should be stored outside of the
21
+ # paths available to the HTTP server.
22
+ #
23
+ # Example:
24
+ #
25
+ # htgroup = WEBrick::HTTPAuth::Htgroup.new 'my_group_file'
26
+ # htgroup.add 'superheroes', %w[spiderman batman]
27
+ #
28
+ # htgroup.members('superheroes').include? 'magneto' # => false
29
+
30
+ class Htgroup
31
+
32
+ ##
33
+ # Open a group database at +path+
34
+
35
+ def initialize(path)
36
+ @path = path
37
+ @mtime = Time.at(0)
38
+ @group = Hash.new
39
+ File.open(@path,"a").close unless File.exist?(@path)
40
+ reload
41
+ end
42
+
43
+ ##
44
+ # Reload groups from the database
45
+
46
+ def reload
47
+ if (mtime = File::mtime(@path)) > @mtime
48
+ @group.clear
49
+ File.open(@path){|io|
50
+ while line = io.gets
51
+ line.chomp!
52
+ group, members = line.split(/:\s*/)
53
+ @group[group] = members.split(/\s+/)
54
+ end
55
+ }
56
+ @mtime = mtime
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Flush the group database. If +output+ is given the database will be
62
+ # written there instead of to the original path.
63
+
64
+ def flush(output=nil)
65
+ output ||= @path
66
+ tmp = Tempfile.create("htgroup", File::dirname(output))
67
+ begin
68
+ @group.keys.sort.each{|group|
69
+ tmp.puts(format("%s: %s", group, self.members(group).join(" ")))
70
+ }
71
+ ensure
72
+ tmp.close
73
+ if $!
74
+ File.unlink(tmp.path)
75
+ else
76
+ return File.rename(tmp.path, output)
77
+ end
78
+ end
79
+ end
80
+
81
+ ##
82
+ # Retrieve the list of members from +group+
83
+
84
+ def members(group)
85
+ reload
86
+ @group[group] || []
87
+ end
88
+
89
+ ##
90
+ # Add an Array of +members+ to +group+
91
+
92
+ def add(group, members)
93
+ @group[group] = members(group) | members
94
+ end
95
+ end
96
+ end
97
+ end