diff options
Diffstat (limited to 'src/mod_http_upload.erl')
-rw-r--r-- | src/mod_http_upload.erl | 185 |
1 files changed, 181 insertions, 4 deletions
diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index 035aa3982..51d7761ab 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -5,7 +5,7 @@ %%% Created : 20 Aug 2015 by Holger Weiss <holger@zedat.fu-berlin.de> %%% %%% -%%% ejabberd, Copyright (C) 2015-2019 ProcessOne +%%% ejabberd, Copyright (C) 2015-2020 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -63,6 +63,7 @@ stop/1, reload/3, depends/2, + mod_doc/0, mod_opt_type/1, mod_options/1]). @@ -223,6 +224,182 @@ mod_options(Host) -> {rm_on_unregister, true}, {thumbnail, false}]. +mod_doc() -> + #{desc => + [?T("This module allows for requesting permissions to " + "upload a file via HTTP as described in " + "https://xmpp.org/extensions/xep-0363.html" + "[XEP-0363: HTTP File Upload]. If the request is accepted, " + "the client receives a URL for uploading the file and " + "another URL from which that file can later be downloaded."), "", + ?T("In order to use this module, it must be configured as " + "a 'request_handler' for 'ejabberd_http' listener.")], + opts => + [{host, + #{desc => ?T("Deprecated. Use 'hosts' instead.")}}, + {hosts, + #{value => ?T("[Host, ...]"), + desc => + ?T("This option defines the Jabber IDs of the service. " + "If the 'hosts' option is not specified, the only Jabber ID will " + "be the hostname of the virtual host with the prefix \"upload.\". " + "The keyword '@HOST@' is replaced with the real virtual host name.")}}, + {name, + #{value => ?T("Name"), + desc => + ?T("A name of the service in the Service Discovery. " + "This will only be displayed by special XMPP clients. " + "The default value is \"HTTP File Upload\".")}}, + {access, + #{value => ?T("AccessName"), + desc => + ?T("This option defines the access rule to limit who is " + "permitted to use the HTTP upload service. " + "The default value is 'local'. If no access rule of " + "that name exists, no user will be allowed to use the service.")}}, + {max_size, + #{value => ?T("Size"), + desc => + ?T("This option limits the acceptable file size. " + "Either a number of bytes (larger than zero) or " + "'infinity' must be specified. " + "The default value is '104857600'.")}}, + {secret_length, + #{value => ?T("Length"), + desc => + ?T("This option defines the length of the random " + "string included in the GET and PUT URLs generated " + "by 'mod_http_upload'. The minimum length is 8 characters, " + "but it is recommended to choose a larger value. " + "The default value is '40'.")}}, + {jid_in_url, + #{value => "node | sha1", + desc => + ?T("When this option is set to 'node', the node identifier " + "of the user's JID (i.e., the user name) is included in " + "the GET and PUT URLs generated by 'mod_http_upload'. " + "Otherwise, a SHA-1 hash of the user's bare JID is " + "included instead. The default value is 'sha1'.")}}, + {thumbnail, + #{value => "true | false", + desc => + ?T("This option specifies whether ejabberd should create " + "thumbnails of uploaded images. If a thumbnail is created, " + "a <thumbnail/> element that contains the download <uri/> " + "and some metadata is returned with the PUT response. " + "The default value is 'false'.")}}, + {file_mode, + #{value => ?T("Permission"), + desc => + ?T("This option defines the permission bits of uploaded files. " + "The bits are specified as an octal number (see the chmod(1) " + "manual page) within double quotes. For example: \"0644\". " + "The default is undefined, which means no explicit permissions " + "will be set.")}}, + {dir_mode, + #{value => ?T("Permission"), + desc => + ?T("This option defines the permission bits of the 'docroot' " + "directory and any directories created during file uploads. " + "The bits are specified as an octal number (see the chmod(1) " + "manual page) within double quotes. For example: \"0755\". " + "The default is undefined, which means no explicit permissions " + "will be set.")}}, + {docroot, + #{value => ?T("Path"), + desc => + ?T("Uploaded files are stored below the directory specified " + "(as an absolute path) with this option. The keyword " + "@HOME@ is replaced with the home directory of the user " + "running ejabberd, and the keyword @HOST@ with the virtual " + "host name. The default value is \"@HOME@/upload\".")}}, + {put_url, + #{value => ?T("URL"), + desc => + ?T("This option specifies the initial part of the PUT URLs " + "used for file uploads. The keyword @HOST@ is replaced " + "with the virtual host name. NOTE: different virtual " + "hosts cannot use the same PUT URL. " + "The default value is \"https://@HOST@:5443\".")}}, + {get_url, + #{value => ?T("URL"), + desc => + ?T("This option specifies the initial part of the GET URLs " + "used for downloading the files. By default, it is set " + "to the same value as 'put_url'. The keyword @HOST@ is " + "replaced with the virtual host name. NOTE: if GET requests " + "are handled by 'mod_http_upload', the 'get_url' must match the " + "'put_url'. Setting it to a different value only makes " + "sense if an external web server or 'mod_http_fileserver' " + "is used to serve the uploaded files.")}}, + {service_url, + #{desc => ?T("Deprecated.")}}, + {custom_headers, + #{value => "{Name: Value}", + desc => + ?T("This option specifies additional header fields to be " + "included in all HTTP responses. By default no custom " + "headers are included.")}}, + {external_secret, + #{value => ?T("Text"), + desc => + ?T("This option makes it possible to offload all HTTP " + "Upload processing to a separate HTTP server. " + "Both ejabberd and the HTTP server should share this " + "secret and behave exactly as described at " + "https://modules.prosody.im/mod_http_upload_external.html" + "[Prosody's mod_http_upload_external] in the " + "'Implementation' section. There is no default value.")}}, + {rm_on_unregister, + #{value => "true | false", + desc => + ?T("This option specifies whether files uploaded by a user " + "should be removed when that user is unregistered. " + "The default value is 'true'.")}}, + {vcard, + #{value => ?T("vCard"), + desc => + ?T("A custom vCard of the service that will be displayed " + "by some XMPP clients in Service Discovery. The value of " + "'vCard' is a YAML map constructed from an XML representation " + "of vCard. Since the representation has no attributes, " + "the mapping is straightforward."), + example => + [{?T("For example, the following XML representation of vCard:"), + ["<vCard xmlns='vcard-temp'>", + " <FN>Conferences</FN>", + " <ADR>", + " <WORK/>", + " <STREET>Elm Street</STREET>", + " </ADR>", + "</vCard>"]}, + {?T("will be translated to:"), + ["vcard:", + " fn: Conferences", + " adr:", + " -", + " work: true", + " street: Elm Street"]}]}}], + example => + ["listen:", + " ...", + " -", + " port: 5443", + " module: ejabberd_http", + " tls: true", + " request_handlers:", + " ...", + " /upload: mod_http_upload", + " ...", + " ...", + "", + "modules:", + " ...", + " mod_http_upload:", + " docroot: /ejabberd/upload", + " put_url: \"https://@HOST@:5443/upload\"", + " ..."]}. + -spec depends(binary(), gen_mod:opts()) -> [{module(), hard | soft}]. depends(_Host, _Opts) -> []. @@ -368,7 +545,7 @@ process(_LocalPath, #request{method = 'PUT', host = Host, ip = IP, ok -> http_response(201, CustomHeaders); {ok, Headers, OutData} -> - http_response(201, Headers ++ CustomHeaders, OutData); + http_response(201, ejabberd_http:apply_custom_headers(Headers, CustomHeaders), OutData); {error, closed} -> ?DEBUG("Cannot store file ~ts from ~ts for ~ts: connection closed", [Path, encode_addr(IP), Host]), @@ -418,7 +595,7 @@ process(_LocalPath, #request{method = Method, host = Host, ip = IP} = Request) $", FileName/binary, $">>}] end, Headers2 = [{<<"Content-Type">>, ContentType} | Headers1], - Headers3 = Headers2 ++ CustomHeaders, + Headers3 = ejabberd_http:apply_custom_headers(Headers2, CustomHeaders), http_response(200, Headers3, {file, Path}); {error, eacces} -> ?WARNING_MSG("Cannot serve ~ts to ~ts: Permission denied", @@ -456,7 +633,7 @@ process(_LocalPath, #request{method = 'OPTIONS', host = Host, try gen_server:call(Proc, get_conf, ?CALL_TIMEOUT) of {ok, _DocRoot, CustomHeaders} -> AllowHeader = {<<"Allow">>, <<"OPTIONS, HEAD, GET, PUT">>}, - http_response(200, [AllowHeader | CustomHeaders]) + http_response(200, ejabberd_http:apply_custom_headers([AllowHeader], CustomHeaders)) catch exit:{noproc, _} -> ?WARNING_MSG("Cannot handle OPTIONS request from ~ts for ~ts: " |