Project1 #2 - Wikipedia Search
Tags: django, cs50w, webdev, backend
Published: 2021-02-14 20:46:24


<a name="top"></a>
After completing the first 2 specifications in the last post, this week focus is on completing the 3rd spec - a wiki search functionality. 

>  * [▶️ 3rd Specification](#3rd-specification)  
>  * [▶️ Django Learning](#django-learning)  
>    * [1️⃣ View must return an HttpResponse](#view)  
>    * [2️⃣ Django Cross-Site Scripting protection (XSS👿)](#xss) 
>  * [▶️ Conclusion](#conclusion)

---
<a name="3rd-specification"></a>
## ▶️ 3rd Specification [↑top](#top)

Search: Allow the user to type a query into the search box in the sidebar to search for an encyclopedia entry.

* If the query matches the name of an encyclopedia entry, the user should be redirected to that entry’s page.
* If the query does not match the name of an encyclopedia entry, the user should instead be taken to a search results page that displays a list of all encyclopedia entries that have the query as a substring. For example, if the search query were `Py`, then `Python` should appear in the search results.
* Clicking on any of the entry names on the search results page should take the user to that entry’s page.

---
<a name="django-learning"></a>
## ▶️ Django Learning [↑top](#top)

Before jumping🦘 into what I have learnt, below is a demo of the 3rd spec. 
![Demo of 3rd Spec](https://dev-to-uploads.s3.amazonaws.com/i/7kw0knnh9txgtmvzzmwc.gif)

<a name="view"></a>
### 1️⃣ View must return an HttpResponse [↑top](#top)
The error❌ "The view didn't return an HttpResponse object. It returned None instead" is shown when a search query GET request is sent to the server. 
* The `index()` function shown below is the function the server routes to when the GET request is received. 

```py
def index(request):
    if request.GET.get('q'):
        search(request, request.GET['q'])
    else:
        return render(request, "encyclopedia/index.html", {
            "entries": util.list_entries()
    })

# ...
# ...

def search(request, query):
    fuzzy_match = []
    # ...
    # ...
    return render(request, "encyclopedia/result.html", {
        "query": query,
        "results": fuzzy_match
    })
```

As with many mistakes, when revisited it looks incredible obvious. This time the root cause is lack of a `return` statement when calling `search()`. This [stackoverflow question](https://stackoverflow.com/questions/26258905/the-view-didnt-return-an-httpresponse-object-it-returned-none-instead) points me to the right direction when I was debugging this issue. 

<a name="xss"></a>
### 2️⃣ Django Cross-Site Scripting protection (XSS👿) [↑top](#top)

When working on rendering the query string in the scenario that no result matches the query string, I noticed the possibility of XSS. 

A simple illustration that I had in mind is a query as shown below:
```
http://127.0.0.1:8000/?q="</li></ul><script>alert("test")</script>

OR simply enter the text below into the search box

"</li></ul><script>alert("test")</script>
```
XSS vulnerability in action 👾
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/imyqofwg1rtrxe4exgsq.gif)


Fortunately Django has `autoescape`([documentation](https://docs.djangoproject.com/en/3.1/ref/templates/builtins/)) on by default😇. Thus the demo above will not be possible. 

It can be made possible to confirm the possibility of XSS by explicitly turning off `autoescape`.
```html
{% autoescape off %}
    {{ untrusted user controlled input text to be rendered }}
{% endautoescape %}
```

---
<a name="Conclusion"></a>
## ▶️ Conclusion [↑top](#top)
That's all for this post, next up - creating and editing wiki pages! 

P/S: On related note regarding XSS, I imagine it will not be possible for XSS to occur by using the wiki page creation too. Will certainly keep you posted if it turns out otherwise 😉