summaryrefslogtreecommitdiffstats
path: root/roles/modernpaste/files/modern-paste.conf
blob: 3a7e3210836265d32f90f3a48a2a74e3c52a216e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
WSGIDaemonProcess stickynotes2modernpaste user=apache group=apache threads=5
WSGIScriptAlias /stickynotes2modernpaste /usr/share/stickynotes2modernpaste/stickynotes2modernpaste.wsgi
WSGISocketPrefix run/wsgi

# Grab a cup of coffee, a light snack, and turn on some classical music.
# You're in for a bit of a novel.
#
# The below rules are worthy of some comment so that later on when I (or
# heaven forbid anyone else) have to revisit them for some horrible reason,
# they can be referred to and maybe (but unlikely) useful.
#
# Chapter 1. Background.
#
# The rewrite rules exist solely for the purpose of continuing to support old
# `fpaste` (the CLI app). This is in the process of being rewritten, and one
# day we won't have to support it anymore. But for now, we do, because it's on
# live media (and, I believe, Desktop installs, by default), and when a user is
# having issues and asking for help in IRC, they need to be able to use
# `fpaste` to do so. So, that is why we care about `fpaste` in its current
# (F25-F26) form.
#
# You see, fpaste was written in such a way that it makes a lot of weird
# assumptions that don't hold anymore. I will not speculate on why it was
# written the way it was, but I _will_ briefly outline some of the intricacies
# of supporting it.
#
# First off the workflow is something like this:
#   1. User wants to paste some text. Who knows why they want to do this. Maybe
#      they are bored and want to see how broken our rewrite rules are. Maybe
#      they hate me and want to see me cry trying to fix them. Who knows?!
#
#   2. The fpaste client makes a POST on their behalf to /. This POST payload
#      includes the text of the paste and some other information (paste
#      language, etc).
#
#   3. The server sees the POST, matches it against our rules below, and
#      decides that it needs to redirect them to stickynotes2modernpaste, a
#      custom Flask app that I (relrod) wrote so that we could handle requests
#      that are in the form our old stickynotes pastebin accepted, and proxy
#      them to modernpaste.
#
#      Note that this matches the first set of crazy RewriteConds below. We
#      only want to send CLI users there, and only when they POST to /. At
#      this point, at least.
#
#   4. sn2mp says "okay cool," proxies the paste to modernpaste via its JSON
#      API, and returns back to fpaste a JSON blob that contains JSON with two
#      keys that fpaste requires exists. In our response, one of them is always
#      an empty string, and the other is the id of the paste, prefixed with
#      "paste/".
#
#   5. At this point, fpaste has enough information to return a URL to the
#      paste. However, things are not all okay in the world. You see, fpaste
#      wants to show a short-url too. Apparently people don't like typing or
#      something. To generate a short-url, the fpaste client sends another POST
#      to us, at the path "/paste/[the paste id]//". In the past, when it would
#      do this, stickynotes would return a JSON blob that included the
#      short-url. In fact, it would always include the short-url at the
#      third-line from the last in its JSON response, and the fpaste client
#      hardcoded that assumption. See Chapter 2 for information about the "//".
#
#   6. When we get this second POST, we again send the client to sn2mp. We add
#      a few more crazy RewriteConds to ensure that we only add this behavior
#      for fpaste and not most users. We know paste IDs are 22-24 characters
#      long (as per https://github.com/LINKIWI/modern-paste/pull/33) and that
#      the client will always POST to "/paste/[the paste id]//". So we match on
#      that. If we match, sn2mp will take everything after its name and append
#      it to the URL that ultimately gets shipped to da.gd for shortening. Then
#      it returns a (malformed) JSON blob that is written in exactly the way
#      fpaste expects.
#
#   7. Then fpaste shows the user both URLs, and all is okay.
#
# Chapter 2. Trailing slashes.
#
# The fpaste client defaults to private mode, but modernpaste doesn't support
# that, per se. You can password-protect pastes, but that's about it.
#
# However, they way stickynotes worked, it used /[paste id]/[secret] when a
# paste was private. Since modernpaste does things differently, sn2mp never
# returns the [secret] part of that URL. Or rather, it returns the empty string
# in its place. This means, by default (private mode = true), fpaste will
# both render, and internally use, a URL that has /[paste id]/[secret]. But
# since [secret] is the empty string, this is equivalent to /[paste id]/, with
# the trailing slash.
#
# To make matters worse, this little gem is found in the fpaste procedure for
# doing the second POST (#5 and 6 above):
#
#    eq = urllib.request.Request(url=long_url+'/', data=params.encode())
#
# Yep, it adds a '/' for the second POST. So we get POSTs to
# /paste/[paste id]// during the second POST.
#
# Our capture of the paste ID below (the ".{22,24}" part) will match the first
# trailing slash, but not the second (because of the /$ that comes after).
# Nevertheless sn2mp handles all three cases anyway, and will STRIP OFF
# trailing slashes if they occur 0, 1, or 2 times.
#
# Lastly, the long url that fpaste shows the user contains one trailing slash
# (due to the /[secret] part from how stickynotes worked). So we add one final
# rewrite that redirects users who go to that, to the non-slash version.
#
# If you have made it this far, you are a champion. You should get a badge.
#
# Warm regards and good luck,
#   relrod

RewriteEngine on
#LogLevel alert rewrite:trace6
RewriteRule login / [L,R]

RewriteCond %{HTTP_USER_AGENT} ^fpaste\/0\.3.*$ [OR]
RewriteCond %{HTTP_USER_AGENT} ^Python\-urllib.*$
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^/$ /stickynotes2modernpaste/$1 [L,PT]

RewriteCond %{HTTP_USER_AGENT} ^fpaste\/0\.3.*$ [OR]
RewriteCond %{HTTP_USER_AGENT} ^Python\-urllib.*$
RewriteCond %{REQUEST_METHOD} POST
RewriteRule ^/paste/(.{22,24})/$ /stickynotes2modernpaste/paste/$1 [L,PT]

# Otherwise, if we're given a URL with a trailing slash, kill it.
RewriteRule ^/paste/([^/]{22,24})/$ /paste/$1 [R,L]

WSGIScriptAlias / /usr/share/modern-paste/modern_paste.wsgi

<Directory /usr/share/stickynotes2modernpaste>
    WSGIProcessGroup stickynotes2modernpaste
    WSGIApplicationGroup %{GLOBAL}
    WSGIScriptReloading On
    Order deny,allow
    Require all granted
</Directory>

<Directory /usr/share/modern-paste>
  Require all granted
</Directory>

DocumentRoot /usr/share/modern-paste
#ErrorLog logs/modern-paste-error.log
#CustomLog logs/modern-paste-access.log combined
#LogLevel info