app.rb 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. require './environment.rb'
  2. require './app_helpers.rb'
  3. use Rack::Session::Cookie, key: 'neocities',
  4. path: '/',
  5. expire_after: 31556926, # one year in seconds
  6. secret: $config['session_secret'],
  7. httponly: true,
  8. same_site: :lax,
  9. secure: ENV['RACK_ENV'] == 'production'
  10. use Rack::TempfileReaper
  11. helpers do
  12. def site_change_file_display_class(filename)
  13. return 'html' if filename.match(Site::HTML_REGEX)
  14. return 'image' if filename.match(Site::IMAGE_REGEX)
  15. 'misc'
  16. end
  17. def csrf_token_input_html
  18. %{<input name="csrf_token" type="hidden" value="#{csrf_token}">}
  19. end
  20. def hcaptcha_input
  21. %{
  22. <script src="https://hcaptcha.com/1/api.js" async defer></script>
  23. <div id="captcha_input" class="h-captcha" data-sitekey="#{$config['hcaptcha_site_key']}"></div>
  24. }
  25. end
  26. end
  27. set :protection, :frame_options => "DENY"
  28. GEOCITIES_NEIGHBORHOODS = %w{
  29. area51
  30. athens
  31. augusta
  32. baja
  33. bourbonstreet
  34. capecanaveral
  35. capitolhill
  36. collegepark
  37. colosseum
  38. enchantedforest
  39. hollywood
  40. motorcity
  41. napavalley
  42. nashville
  43. petsburgh
  44. pipeline
  45. rainforest
  46. researchtriangle
  47. siliconvalley
  48. soho
  49. sunsetstrip
  50. timessquare
  51. televisioncity
  52. tokyo
  53. vienna
  54. westhollywood
  55. yosemite
  56. }.freeze
  57. def redirect_to_internet_archive_for_geocities_sites
  58. match = request.path.match /^\/(\w+)\/.+$/i
  59. if match && GEOCITIES_NEIGHBORHOODS.include?(match.captures.first.downcase)
  60. redirect "https://wayback.archive.org/http://geocities.com/#{request.path}"
  61. end
  62. end
  63. before do
  64. if request.path.match /^\/api\//i
  65. @api = true
  66. content_type :json
  67. elsif request.path.match /^\/webhooks\//
  68. # Skips the CSRF/validation check for stripe web hooks
  69. elsif current_site && current_site.email_not_validated? && !(request.path =~ /^\/site\/.+\/confirm_email|^\/settings\/change_email|^\/welcome|^\/supporter|^\/signout/)
  70. redirect "/site/#{current_site.username}/confirm_email"
  71. elsif current_site && current_site.phone_verification_needed? && !(request.path =~ /^\/site\/.+\/confirm_email|^\/settings\/change_email|^\/site\/.+\/confirm_phone|^\/welcome|^\/supporter|^\/signout/)
  72. redirect "/site/#{current_site.username}/confirm_phone"
  73. elsif current_site && current_site.tutorial_required && !(request.path =~ /^\/site\/.+\/confirm_email|^\/settings\/change_email|^\/site\/.+\/confirm_phone|^\/welcome|^\/supporter|^\/tutorial\/.+/)
  74. redirect '/tutorial/html/1'
  75. else
  76. content_type :html, 'charset' => 'utf-8'
  77. redirect '/' if request.post? && !csrf_safe?
  78. end
  79. end
  80. after do
  81. if @api
  82. request.session_options[:skip] = true
  83. end
  84. end
  85. after do
  86. response.headers['Content-Security-Policy'] = %{default-src 'self' data: blob: 'unsafe-inline'; script-src 'self' blob: 'unsafe-inline' 'unsafe-eval' https://hcaptcha.com https://*.hcaptcha.com https://js.stripe.com; style-src 'self' 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://hcaptcha.com https://*.hcaptcha.com https://api.stripe.com; frame-src 'self' https://hcaptcha.com https://*.hcaptcha.com https://js.stripe.com} unless self.class.development?
  87. end
  88. not_found do
  89. api_not_found if @api
  90. redirect_to_internet_archive_for_geocities_sites
  91. @title = 'Not Found'
  92. erb :'not_found'
  93. end
  94. error do
  95. =begin
  96. EmailWorker.perform_async({
  97. from: 'web@neocities.org',
  98. to: 'errors@neocities.org',
  99. subject: "[Neocities Error] #{env['sinatra.error'].class}: #{env['sinatra.error'].message}",
  100. body: erb(:'templates/email/error', layout: false),
  101. no_footer: true
  102. })
  103. =end
  104. if @api
  105. api_error 500, 'server_error', 'there has been an unknown server error, please try again later'
  106. end
  107. erb :'error'
  108. end
  109. Dir['./app/**/*.rb'].each {|f| require f}