Use session provider in json base page
[Sone.git] / src / main / java / net / pterodactylus / sone / web / ajax / JsonPage.java
1 /*
2  * Sone - JsonPage.java - Copyright © 2010–2016 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.web.ajax;
19
20 import static java.util.logging.Logger.getLogger;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.PrintWriter;
26 import java.net.URI;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.annotation.Nonnull;
31
32 import net.pterodactylus.sone.data.Sone;
33 import net.pterodactylus.sone.web.SessionProvider;
34 import net.pterodactylus.sone.web.WebInterface;
35 import net.pterodactylus.sone.web.page.FreenetPage;
36 import net.pterodactylus.sone.web.page.FreenetRequest;
37 import net.pterodactylus.util.io.Closer;
38 import net.pterodactylus.util.web.Page;
39 import net.pterodactylus.util.web.Response;
40
41 import com.fasterxml.jackson.databind.ObjectMapper;
42 import freenet.clients.http.ToadletContext;
43
44 /**
45  * A JSON page is a specialized {@link Page} that will always return a JSON
46  * object to the browser, e.g. for use with AJAX or other scripting frameworks.
47  *
48  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
49  */
50 public abstract class JsonPage implements FreenetPage {
51
52         /** The logger. */
53         private static final Logger logger = getLogger(JsonPage.class.getName());
54
55         /** The JSON serializer. */
56         private static final ObjectMapper objectMapper = new ObjectMapper();
57
58         /** The path of the page. */
59         private final String path;
60
61         /** The Sone web interface. */
62         protected final WebInterface webInterface;
63         private final SessionProvider sessionProvider;
64
65         /**
66          * Creates a new JSON page at the given path.
67          *
68          * @param path
69          *            The path of the page
70          * @param webInterface
71          *            The Sone web interface
72          */
73         public JsonPage(String path, WebInterface webInterface) {
74                 this.path = path;
75                 this.webInterface = webInterface;
76                 this.sessionProvider = webInterface;
77         }
78
79         //
80         // ACCESSORS
81         //
82
83         protected Sone getCurrentSone(ToadletContext toadletContext) {
84                 return sessionProvider.getCurrentSone(toadletContext, true);
85         }
86
87         protected Sone getCurrentSone(ToadletContext toadletContext, boolean createSession) {
88                 return sessionProvider.getCurrentSone(toadletContext, createSession);
89         }
90
91         //
92         // METHODS FOR SUBCLASSES TO OVERRIDE
93         //
94
95         /**
96          * This method is called to create the JSON object that is returned back to
97          * the browser.
98          *
99          * @param request
100          *            The request to handle
101          * @return The created JSON object
102          */
103         protected abstract JsonReturnObject createJsonObject(FreenetRequest request);
104
105         /**
106          * Returns whether this command needs the form password for authentication
107          * and to prevent abuse.
108          *
109          * @return {@code true} if the form password (given as “formPassword”) is
110          *         required, {@code false} otherwise
111          */
112         @SuppressWarnings("static-method")
113         protected boolean needsFormPassword() {
114                 return true;
115         }
116
117         /**
118          * Returns whether this page requires the user to be logged in.
119          *
120          * @return {@code true} if the user needs to be logged in to use this page,
121          *         {@code false} otherwise
122          */
123         @SuppressWarnings("static-method")
124         protected boolean requiresLogin() {
125                 return true;
126         }
127
128         //
129         // PROTECTED METHODS
130         //
131
132         /**
133          * Creates a success reply.
134          *
135          * @return A reply signaling success
136          */
137         @Nonnull
138         protected static JsonReturnObject createSuccessJsonObject() {
139                 return new JsonReturnObject(true);
140         }
141
142         /**
143          * Creates an error reply.
144          *
145          * @param error
146          *            The error that has occured
147          * @return The JSON object, signalling failure and the error code
148          */
149         @Nonnull
150         protected static JsonReturnObject createErrorJsonObject(String error) {
151                 return new JsonErrorReturnObject(error);
152         }
153
154         //
155         // PAGE METHODS
156         //
157
158         /**
159          * {@inheritDoc}
160          */
161         @Override
162         public String getPath() {
163                 return path;
164         }
165
166         /**
167          * {@inheritDoc}
168          */
169         @Override
170         public boolean isPrefixPage() {
171                 return false;
172         }
173
174         /**
175          * {@inheritDoc}
176          */
177         @Override
178         public Response handleRequest(FreenetRequest request, Response response) throws IOException {
179                 if (webInterface.getCore().getPreferences().isRequireFullAccess() && !request.getToadletContext().isAllowedFullAccess()) {
180                         return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required")));
181                 }
182                 if (needsFormPassword()) {
183                         String formPassword = request.getHttpRequest().getParam("formPassword");
184                         if (!webInterface.getFormPassword().equals(formPassword)) {
185                                 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required")));
186                         }
187                 }
188                 if (requiresLogin()) {
189                         if (getCurrentSone(request.getToadletContext(), false) == null) {
190                                 return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required")));
191                         }
192                 }
193                 try {
194                         JsonReturnObject jsonObject = createJsonObject(request);
195                         return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(objectMapper.writeValueAsString(jsonObject));
196                 } catch (Exception e1) {
197                         logger.log(Level.WARNING, "Error executing JSON page!", e1);
198                         return response.setStatusCode(500).setStatusText(e1.getMessage()).setContentType("text/plain").write(dumpStackTrace(e1));
199                 }
200         }
201
202         /**
203          * {@inheritDoc}
204          */
205         @Override
206         public boolean isLinkExcepted(URI link) {
207                 return false;
208         }
209
210         //
211         // PRIVATE METHODS
212         //
213
214         /**
215          * Returns a byte array containing the stack trace of the given throwable.
216          *
217          * @param t
218          *            The throwable whose stack trace to dump into an array
219          * @return The array with the stack trace, or an empty array if the stack
220          *         trace could not be dumped
221          */
222         private static byte[] dumpStackTrace(Throwable t) {
223                 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
224                 OutputStreamWriter writer = null;
225                 PrintWriter printWriter = null;
226                 try {
227                         writer = new OutputStreamWriter(byteArrayOutputStream, "uTF-8");
228                         printWriter = new PrintWriter(writer);
229                         t.printStackTrace(printWriter);
230                         byteArrayOutputStream.flush();
231                         return byteArrayOutputStream.toByteArray();
232                 } catch (IOException ioe1) {
233                         /* quite not possible. */
234                         return new byte[0];
235                 } finally {
236                         Closer.close(printWriter);
237                         Closer.close(writer);
238                         Closer.close(byteArrayOutputStream);
239                 }
240         }
241
242 }