fetch url for OStatus to know if it is a/c or status
[akkoma] / lib / pleroma / web / twitter_api / controllers / util_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.TwitterAPI.UtilController do
6 use Pleroma.Web, :controller
7
8 require Logger
9
10 alias Comeonin.Pbkdf2
11 alias Pleroma.Activity
12 alias Pleroma.Emoji
13 alias Pleroma.Notification
14 alias Pleroma.PasswordResetToken
15 alias Pleroma.Repo
16 alias Pleroma.User
17 alias Pleroma.Web
18 alias Pleroma.Web.ActivityPub.ActivityPub
19 alias Pleroma.Web.CommonAPI
20 alias Pleroma.Web.OStatus
21 alias Pleroma.Web.WebFinger
22
23 def show_password_reset(conn, %{"token" => token}) do
24 with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
25 %User{} = user <- Repo.get(User, token.user_id) do
26 render(conn, "password_reset.html", %{
27 token: token,
28 user: user
29 })
30 else
31 _e -> render(conn, "invalid_token.html")
32 end
33 end
34
35 def password_reset(conn, %{"data" => data}) do
36 with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do
37 render(conn, "password_reset_success.html")
38 else
39 _e -> render(conn, "password_reset_failed.html")
40 end
41 end
42
43 def help_test(conn, _params) do
44 json(conn, "ok")
45 end
46
47 def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
48 with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do
49 conn
50 |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
51 else
52 _e ->
53 render(conn, "subscribe.html", %{
54 nickname: nick,
55 avatar: nil,
56 error: "Could not find user"
57 })
58 end
59 end
60
61 def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
62 with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
63 %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
64 conn
65 |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
66 else
67 _e ->
68 render(conn, "subscribe.html", %{
69 nickname: nick,
70 avatar: nil,
71 error: "Something went wrong."
72 })
73 end
74 end
75
76 def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
77 case is_status?(acct) do
78 true ->
79 {:ok, object} = ActivityPub.fetch_object_from_id(acct)
80 %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
81 redirect(conn, to: "/notice/#{activity_id}")
82
83 false ->
84 {err, followee} = OStatus.find_or_make_user(acct)
85 avatar = User.avatar_url(followee)
86 name = followee.nickname
87 id = followee.id
88
89 if !!user do
90 conn
91 |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
92 else
93 conn
94 |> render("follow_login.html", %{
95 error: false,
96 acct: acct,
97 avatar: avatar,
98 name: name,
99 id: id
100 })
101 end
102 end
103 end
104
105 defp is_status?(acct) do
106 case ActivityPub.fetch_and_contain_remote_object_from_id(acct) do
107 {:ok, %{"type" => "Note"}} -> true
108 _ -> false
109 end
110 end
111
112 def do_remote_follow(conn, %{
113 "authorization" => %{"name" => username, "password" => password, "id" => id}
114 }) do
115 followee = Repo.get(User, id)
116 avatar = User.avatar_url(followee)
117 name = followee.nickname
118
119 with %User{} = user <- User.get_cached_by_nickname(username),
120 true <- Pbkdf2.checkpw(password, user.password_hash),
121 %User{} = _followed <- Repo.get(User, id),
122 {:ok, follower} <- User.follow(user, followee),
123 {:ok, _activity} <- ActivityPub.follow(follower, followee) do
124 conn
125 |> render("followed.html", %{error: false})
126 else
127 # Was already following user
128 {:error, "Could not follow user:" <> _rest} ->
129 render(conn, "followed.html", %{error: false})
130
131 _e ->
132 conn
133 |> render("follow_login.html", %{
134 error: "Wrong username or password",
135 id: id,
136 name: name,
137 avatar: avatar
138 })
139 end
140 end
141
142 def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
143 with %User{} = followee <- Repo.get(User, id),
144 {:ok, follower} <- User.follow(user, followee),
145 {:ok, _activity} <- ActivityPub.follow(follower, followee) do
146 conn
147 |> render("followed.html", %{error: false})
148 else
149 # Was already following user
150 {:error, "Could not follow user:" <> _rest} ->
151 conn
152 |> render("followed.html", %{error: false})
153
154 e ->
155 Logger.debug("Remote follow failed with error #{inspect(e)}")
156
157 conn
158 |> render("followed.html", %{error: inspect(e)})
159 end
160 end
161
162 def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
163 with {:ok, _} <- Notification.read_one(user, notification_id) do
164 json(conn, %{status: "success"})
165 else
166 {:error, message} ->
167 conn
168 |> put_resp_content_type("application/json")
169 |> send_resp(403, Jason.encode!(%{"error" => message}))
170 end
171 end
172
173 def config(conn, _params) do
174 instance = Pleroma.Config.get(:instance)
175 instance_fe = Pleroma.Config.get(:fe)
176 instance_chat = Pleroma.Config.get(:chat)
177
178 case get_format(conn) do
179 "xml" ->
180 response = """
181 <config>
182 <site>
183 <name>#{Keyword.get(instance, :name)}</name>
184 <site>#{Web.base_url()}</site>
185 <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
186 <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
187 </site>
188 </config>
189 """
190
191 conn
192 |> put_resp_content_type("application/xml")
193 |> send_resp(200, response)
194
195 _ ->
196 vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
197
198 uploadlimit = %{
199 uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
200 avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
201 backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
202 bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
203 }
204
205 data = %{
206 name: Keyword.get(instance, :name),
207 description: Keyword.get(instance, :description),
208 server: Web.base_url(),
209 textlimit: to_string(Keyword.get(instance, :limit)),
210 uploadlimit: uploadlimit,
211 closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
212 private: if(Keyword.get(instance, :public, true), do: "0", else: "1"),
213 vapidPublicKey: vapid_public_key,
214 accountActivationRequired:
215 if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"),
216 invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0"),
217 safeDMMentionsEnabled:
218 if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0")
219 }
220
221 pleroma_fe =
222 if instance_fe do
223 %{
224 theme: Keyword.get(instance_fe, :theme),
225 background: Keyword.get(instance_fe, :background),
226 logo: Keyword.get(instance_fe, :logo),
227 logoMask: Keyword.get(instance_fe, :logo_mask),
228 logoMargin: Keyword.get(instance_fe, :logo_margin),
229 redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login),
230 redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login),
231 chatDisabled: !Keyword.get(instance_chat, :enabled),
232 showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel),
233 scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled),
234 formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled),
235 collapseMessageWithSubject:
236 Keyword.get(instance_fe, :collapse_message_with_subject),
237 hidePostStats: Keyword.get(instance_fe, :hide_post_stats),
238 hideUserStats: Keyword.get(instance_fe, :hide_user_stats),
239 scopeCopy: Keyword.get(instance_fe, :scope_copy),
240 subjectLineBehavior: Keyword.get(instance_fe, :subject_line_behavior),
241 alwaysShowSubjectInput: Keyword.get(instance_fe, :always_show_subject_input)
242 }
243 else
244 Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
245 end
246
247 managed_config = Keyword.get(instance, :managed_config)
248
249 data =
250 if managed_config do
251 data |> Map.put("pleromafe", pleroma_fe)
252 else
253 data
254 end
255
256 json(conn, %{site: data})
257 end
258 end
259
260 def frontend_configurations(conn, _params) do
261 config =
262 Pleroma.Config.get(:frontend_configurations, %{})
263 |> Enum.into(%{})
264
265 json(conn, config)
266 end
267
268 def version(conn, _params) do
269 version = Pleroma.Application.named_version()
270
271 case get_format(conn) do
272 "xml" ->
273 response = "<version>#{version}</version>"
274
275 conn
276 |> put_resp_content_type("application/xml")
277 |> send_resp(200, response)
278
279 _ ->
280 json(conn, version)
281 end
282 end
283
284 def emoji(conn, _params) do
285 json(conn, Enum.into(Emoji.get_all(), %{}))
286 end
287
288 def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
289 follow_import(conn, %{"list" => File.read!(listfile.path)})
290 end
291
292 def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
293 with followed_identifiers <- String.split(list),
294 {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do
295 json(conn, "job started")
296 end
297 end
298
299 def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
300 blocks_import(conn, %{"list" => File.read!(listfile.path)})
301 end
302
303 def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
304 with blocked_identifiers <- String.split(list),
305 {:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do
306 json(conn, "job started")
307 end
308 end
309
310 def change_password(%{assigns: %{user: user}} = conn, params) do
311 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
312 {:ok, user} ->
313 with {:ok, _user} <-
314 User.reset_password(user, %{
315 password: params["new_password"],
316 password_confirmation: params["new_password_confirmation"]
317 }) do
318 json(conn, %{status: "success"})
319 else
320 {:error, changeset} ->
321 {_, {error, _}} = Enum.at(changeset.errors, 0)
322 json(conn, %{error: "New password #{error}."})
323
324 _ ->
325 json(conn, %{error: "Unable to change password."})
326 end
327
328 {:error, msg} ->
329 json(conn, %{error: msg})
330 end
331 end
332
333 def delete_account(%{assigns: %{user: user}} = conn, params) do
334 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
335 {:ok, user} ->
336 Task.start(fn -> User.delete(user) end)
337 json(conn, %{status: "success"})
338
339 {:error, msg} ->
340 json(conn, %{error: msg})
341 end
342 end
343
344 def captcha(conn, _params) do
345 json(conn, Pleroma.Captcha.new())
346 end
347 end