Fix CSRF issues
GET routes are not protected against CSRF. This commit changes the needed URLs to POST and replace simple links with forms. Thanks @fdb-hiroshima for noticing it!
This commit is contained in:
		
							parent
							
								
									eb24ba1774
								
							
						
					
					
						commit
						d8ca1d70b7
					
				
							
								
								
									
										21
									
								
								po/gl.po
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								po/gl.po
									
									
									
									
									
								
							| @ -325,7 +325,8 @@ msgstr[1] "{{ count }} autoras en este blog: " | ||||
| 
 | ||||
| msgid "Login or use your Fediverse account to interact with this article" | ||||
| msgstr "" | ||||
| "Conéctese ou utilice a súa conta no fediverso para interactuar con este artigo" | ||||
| "Conéctese ou utilice a súa conta no fediverso para interactuar con este " | ||||
| "artigo" | ||||
| 
 | ||||
| msgid "Optional" | ||||
| msgstr "Opcional" | ||||
| @ -486,7 +487,6 @@ msgstr "Descrición" | ||||
| msgid "Content warning" | ||||
| msgstr "Aviso sobre o contido" | ||||
| 
 | ||||
| 
 | ||||
| msgid "File" | ||||
| msgstr "Ficheiro" | ||||
| 
 | ||||
| @ -496,7 +496,8 @@ msgstr "Enviar" | ||||
| msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| "Lamentámolo, pero o rexistro está pechado en esta instancia. Intente atopar outra" | ||||
| "Lamentámolo, pero o rexistro está pechado en esta instancia. Intente atopar " | ||||
| "outra" | ||||
| 
 | ||||
| msgid "Subtitle" | ||||
| msgstr "Subtítulo" | ||||
| @ -553,9 +554,10 @@ msgid "" | ||||
| "Something is wrong with your CSRF token. Make sure cookies are enabled in " | ||||
| "you browser, and try reloading this page. If you continue to see this error " | ||||
| "message, please report it." | ||||
| msgstr "Hai un problema co seu testemuño CSRF. Asegúrese de ter as cookies activadas " | ||||
| "no navegador, e recargue a páxina. Si persiste o aviso de este fallo, " | ||||
| " informe por favor." | ||||
| msgstr "" | ||||
| "Hai un problema co seu testemuño CSRF. Asegúrese de ter as cookies activadas " | ||||
| "no navegador, e recargue a páxina. Si persiste o aviso de este fallo,  " | ||||
| "informe por favor." | ||||
| 
 | ||||
| msgid "Administration of {{ instance.name }}" | ||||
| msgstr "Administración de {{ instance_name }}" | ||||
| @ -600,7 +602,12 @@ msgid "Delete your account" | ||||
| msgstr "Eliminar a súa conta" | ||||
| 
 | ||||
| msgid "Sorry, but as an admin, you can't leave your instance." | ||||
| msgstr "Lamentámolo, pero como administradora, non pode deixar a súa instancia." | ||||
| msgstr "" | ||||
| "Lamentámolo, pero como administradora, non pode deixar a súa instancia." | ||||
| 
 | ||||
| msgid "Users" | ||||
| msgstr "Usuarias" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "This post isn't published yet." | ||||
| msgstr "Esto é un borrador, non publicar por agora." | ||||
|  | ||||
| @ -156,7 +156,7 @@ fn admin_instances_paginated(admin: Admin, conn: DbConn, page: Page) -> Template | ||||
|     })) | ||||
| } | ||||
| 
 | ||||
| #[get("/admin/instances/<id>/block")] | ||||
| #[post("/admin/instances/<id>/block")] | ||||
| fn toggle_block(_admin: Admin, conn: DbConn, id: i32) -> Redirect { | ||||
|     if let Some(inst) = Instance::get(&*conn, id) { | ||||
|         inst.toggle_block(&*conn); | ||||
| @ -183,7 +183,7 @@ fn admin_users_paginated(admin: Admin, conn: DbConn, page: Page) -> Template { | ||||
|     })) | ||||
| } | ||||
| 
 | ||||
| #[get("/admin/users/<id>/ban")] | ||||
| #[post("/admin/users/<id>/ban")] | ||||
| fn ban(_admin: Admin, conn: DbConn, id: i32) -> Redirect { | ||||
|     User::get(&*conn, id).map(|u| u.delete(&*conn)); | ||||
|     Redirect::to(uri!(admin_users)) | ||||
|  | ||||
| @ -97,14 +97,14 @@ fn details(id: i32, user: User, conn: DbConn) -> Template { | ||||
|     })) | ||||
| } | ||||
| 
 | ||||
| #[get("/medias/<id>/delete")] | ||||
| #[post("/medias/<id>/delete")] | ||||
| fn delete(id: i32, _user: User, conn: DbConn) -> Redirect { | ||||
|     let media = Media::get(&*conn, id).expect("Media to delete not found"); | ||||
|     media.delete(&*conn); | ||||
|     Redirect::to(uri!(list)) | ||||
| } | ||||
| 
 | ||||
| #[get("/medias/<id>/avatar")] | ||||
| #[post("/medias/<id>/avatar")] | ||||
| fn set_avatar(id: i32, user: User, conn: DbConn) -> Redirect { | ||||
|     let media = Media::get(&*conn, id).expect("Media to delete not found"); | ||||
|     user.set_avatar(&*conn, media.id); | ||||
|  | ||||
| @ -338,7 +338,7 @@ fn create(blog_name: String, data: LenientForm<NewPostForm>, user: User, conn: D | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[get("/~/<blog_name>/<slug>/delete")] | ||||
| #[post("/~/<blog_name>/<slug>/delete")] | ||||
| fn delete(blog_name: String, slug: String, conn: DbConn, user: User, worker: State<Pool<ThunkWorker<()>>>) -> Redirect { | ||||
|     let post = Blog::find_by_fqn(&*conn, blog_name.clone()) | ||||
|         .and_then(|blog| Post::find_by_slug(&*conn, slug.clone(), blog.id)); | ||||
|  | ||||
| @ -118,7 +118,7 @@ fn dashboard_auth() -> Flash<Redirect> { | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| #[get("/@/<name>/follow")] | ||||
| #[post("/@/<name>/follow")] | ||||
| fn follow(name: String, conn: DbConn, user: User, worker: Worker) -> Redirect { | ||||
|     let target = User::find_by_fqn(&*conn, name.clone()).unwrap(); | ||||
|     if let Some(follow) = follows::Follow::find(&*conn, user.id, target.id) { | ||||
| @ -138,7 +138,7 @@ fn follow(name: String, conn: DbConn, user: User, worker: Worker) -> Redirect { | ||||
|     Redirect::to(uri!(details: name = name)) | ||||
| } | ||||
| 
 | ||||
| #[get("/@/<name>/follow", rank = 2)] | ||||
| #[post("/@/<name>/follow", rank = 2)] | ||||
| fn follow_auth(name: String) -> Flash<Redirect> { | ||||
|     utils::requires_login( | ||||
|         "You need to be logged in order to follow someone", | ||||
| @ -225,7 +225,7 @@ fn update(_name: String, conn: DbConn, user: User, data: LenientForm<UpdateUserF | ||||
|     Redirect::to(uri!(me)) | ||||
| } | ||||
| 
 | ||||
| #[get("/@/<name>/delete")] | ||||
| #[post("/@/<name>/delete")] | ||||
| fn delete(name: String, conn: DbConn, user: User, mut cookies: Cookies) -> Redirect { | ||||
|     let account = User::find_by_fqn(&*conn, name.clone()).unwrap(); | ||||
|     if user.id == account.id { | ||||
|  | ||||
| @ -472,6 +472,33 @@ main .article-meta .tags li a { | ||||
|  	width: initial; | ||||
|  } | ||||
| 
 | ||||
| /** Inline forms (containing only CSRF token and a <submit>, for protected links) **/ | ||||
| 
 | ||||
| form.inline { | ||||
|     display: inline; | ||||
|     margin: 0px; | ||||
|     padding: 0px; | ||||
|     width: auto; | ||||
| } | ||||
| 
 | ||||
| form.inline input[type="submit"] { | ||||
|     display: inline-block; | ||||
|     color: #7765E3; | ||||
|     cursor: pointer; | ||||
|     font-size: 1em; | ||||
|     width: auto; | ||||
| } | ||||
| 
 | ||||
| form.inline input[type="submit"]:not(.button) { | ||||
|     margin: 0; | ||||
|     border: none; | ||||
| } | ||||
| 
 | ||||
| form.inline input[type="submit"]:not(.button) { | ||||
|     background: transparent; | ||||
|     color: #7765E3; | ||||
| } | ||||
| 
 | ||||
|  /* Button & Submit */ | ||||
| 
 | ||||
|  .button, input[type="submit"], button { | ||||
|  | ||||
| @ -18,13 +18,13 @@ | ||||
|                     <small>{{ instance.public_domain }}</small> | ||||
|                 </p> | ||||
|                 {% if not instance.local %} | ||||
|                     <a href="/admin/instances/{{ instance.id }}/block"> | ||||
|                     <form class="inline" method="post" action="/admin/instances/{{ instance.id }}/block"> | ||||
|                         {% if instance.blocked %} | ||||
|                             {{ "Unblock" | _ }} | ||||
|                             <input type="submit" value="{{ 'Unblock' | _ }}"> | ||||
|                         {% else %} | ||||
|                             {{ "Block" | _ }} | ||||
|                             <input type="submit" value="{{ 'Block' | _ }}"> | ||||
|                         {% endif %} | ||||
|                     </a> | ||||
|                     </form> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         {% endfor %} | ||||
|  | ||||
| @ -19,9 +19,9 @@ | ||||
|                     <small>@{{ user.username }}</small> | ||||
|                 </p> | ||||
|                 {% if not user.is_admin %} | ||||
|                     <a href="/admin/users/{{ user.id }}/ban"> | ||||
|                         {{ "Ban" | _ }} | ||||
|                     </a> | ||||
|                     <form class="inline" method="post" href="/admin/users/{{ user.id }}/ban"> | ||||
|                         <input type="submit" value="{{ 'Ban' | _ }}"> | ||||
|                     </form> | ||||
|                 {% endif %} | ||||
|             </div> | ||||
|         {% endfor %} | ||||
|  | ||||
| @ -24,8 +24,12 @@ | ||||
|             <code>{{ media.md }}</code> | ||||
|         </div> | ||||
|         <div> | ||||
|             <a href="/medias/{{ media.id }}/avatar" class="button inline-block">{{ "Use as avatar" | _ }}</a> | ||||
|             <a href="/medias/{{ media.id }}/delete" class="button inline-block">{{ "Delete" | _ }}</a> | ||||
|             <form class="inline" method="post" action="/medias/{{ media.id }}/avatar"> | ||||
|                 <input class="button" type="submit" value="{{ 'Use as avatar' | _ }}"> | ||||
|             </form> | ||||
|             <form class="inline" method="post" action="/medias/{{ media.id }}/delete"> | ||||
|                 <input class="button" type="submit" value="{{ 'Delete' | _ }}"> | ||||
|             </form> | ||||
|         </div> | ||||
|     </section> | ||||
| {% endblock content %} | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| {% block content %} | ||||
|     <h1 class="article">{{ article.post.title }}</h1> | ||||
|     <h2 class="article">{{ article.post.subtitle }}</h2> | ||||
|     <p class="article-info"> | ||||
|     <div class="article-info"> | ||||
|         <span class="author">{{ "Written by {{ link_1 }}{{ url }}{{ link_2 }}{{ name | escape }}{{ link_3 }}" | _( | ||||
|             link_1='<a href="/@/', | ||||
|             url=author.fqn, | ||||
| @ -20,19 +20,21 @@ | ||||
|             name=author.name, | ||||
|             link_3="</a>" | ||||
|             ) | ||||
|         }}</a></span> | ||||
|         }}</span> | ||||
|         — | ||||
|         <span class="date">{{ date | date(format="%B %e, %Y") }}</span> | ||||
|         {% if is_author %} | ||||
|             — | ||||
|             <a href="{{ article.url}}edit">{{ "Edit" | _ }}</a> | ||||
|             — | ||||
|             <a href="{{ article.url}}delete" onclick="return confirm('Are you sure you?')">{{ "Delete this article" | _ }}</a> | ||||
|             <form class="inline" method="post" action="{{ article.url}}delete"> | ||||
|                 <input onclick="return confirm('Are you sure you?')" type="submit" value="{{ 'Delete this article' | _ }}"> | ||||
|             </form> | ||||
|         {% endif %} | ||||
|         {%  if not article.post.published %} | ||||
|             <span class="badge">{{ "Draft" }}</span> | ||||
|         {% endif %} | ||||
|     </p> | ||||
|     </div> | ||||
|     <article> | ||||
|         {{ article.post.content | safe }} | ||||
|     </article> | ||||
|  | ||||
| @ -25,7 +25,9 @@ | ||||
| <h2>{{ "Danger zone" | _ }}</h2> | ||||
| <p>{{ "Be very careful, any action taken here can't be cancelled." | _ }} | ||||
| {% if not account.is_admin %} | ||||
|     <p><a class="inline-block button destructive" href="/@/{{ account.fqn }}/delete">{{ "Delete your account" | _ }}</a></p> | ||||
|     <form method="post" action="/@/{{ account.fqn }}/delete"> | ||||
|         <input type="submit" class="inline-block button destructive" value="{{ 'Delete your account' | _ }}"> | ||||
|     </form> | ||||
| {% else %} | ||||
|     <p>{{ "Sorry, but as an admin, you can't leave your instance." | _ }}</p> | ||||
| {% endif %} | ||||
|  | ||||
| @ -23,16 +23,18 @@ | ||||
|     </div> | ||||
| 
 | ||||
|     {% if is_remote %} | ||||
|         <a class="inline-block button" href="{{ user.ap_url }}" target="_blank">{{ "Open on {{ instance_url }}" | _(instance_url=instance_url) }}</a> | ||||
|         <a class="inline-block" href="{{ user.ap_url }}" target="_blank">{{ "Open on {{ instance_url }}" | _(instance_url=instance_url) }}</a> | ||||
|     {% endif %} | ||||
| 
 | ||||
|     {% set not_self = not is_self %} | ||||
|     {% if not_self and (account is defined) %} | ||||
|         <form class="inline" method="post" action="/@/{{ user.fqn }}/follow/"> | ||||
|         {% if follows %} | ||||
|             <a href="/@/{{ user.fqn }}/follow/" class="inline-block button">{{ "Unfollow" | _ }}</a> | ||||
|             <input type="submit" value="{{ 'Unfollow' | _ }}"> | ||||
|         {% else %} | ||||
|             <a href="/@/{{ user.fqn }}/follow/" class="inline-block button">{{ "Follow" | _ }}</a> | ||||
|             <input type="submit" value="{{ 'Follow' | _ }}"> | ||||
|         {% endif %} | ||||
|         </form> | ||||
|     {% endif %} | ||||
| </div> | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user