diff --git a/CONFIGURATION.md b/CONFIGURATION.md deleted file mode 100644 index 51a76d1b7..000000000 --- a/CONFIGURATION.md +++ /dev/null @@ -1,106 +0,0 @@ -# Configuring Pleroma - -In the `config/` directory, you will find the following relevant files: - -* `config.exs`: default base configuration -* `dev.exs`: default additional configuration for `MIX_ENV=dev` -* `prod.exs`: default additional configuration for `MIX_ENV=prod` - - -Do not modify files in the list above. -Instead, overload the settings by editing the following files: - -* `dev.secret.exs`: custom additional configuration for `MIX_ENV=dev` -* `prod.secret.exs`: custom additional configuration for `MIX_ENV=prod` - -## Uploads configuration - -To configure where to upload files, and wether or not -you want to remove automatically EXIF data from pictures -being uploaded. - - config :pleroma, Pleroma.Upload, - uploads: "uploads", - strip_exif: false - -* `uploads`: where to put the uploaded files, relative to pleroma's main directory. -* `strip_exif`: whether or not to remove EXIF data from uploaded pics automatically. - This needs Imagemagick installed on the system ( apt install imagemagick ). - - -## Block functionality - - config :pleroma, :activitypub, - accept_blocks: true, - unfollow_blocked: true, - outgoing_blocks: true - - config :pleroma, :user, deny_follow_blocked: true - -* `accept_blocks`: whether to accept incoming block activities from - other instances -* `unfollow_blocked`: whether blocks result in people getting - unfollowed -* `outgoing_blocks`: whether to federate blocks to other instances -* `deny_follow_blocked`: whether to disallow following an account that - has blocked the user in question - -## Message Rewrite Filters (MRFs) - -Modify incoming and outgoing posts. - - config :pleroma, :instance, - rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy - -`rewrite_policy` specifies which MRF policies to apply. -It can either be a single policy or a list of policies. -Currently, MRFs availible by default are: - -* `Pleroma.Web.ActivityPub.MRF.NoOpPolicy` -* `Pleroma.Web.ActivityPub.MRF.DropPolicy` -* `Pleroma.Web.ActivityPub.MRF.SimplePolicy` -* `Pleroma.Web.ActivityPub.MRF.RejectNonPublic` - -Some policies, such as SimplePolicy and RejectNonPublic, -can be additionally configured in their respective sections. - -### NoOpPolicy - -Does not modify posts (this is the default `rewrite_policy`) - -### DropPolicy - -Drops all posts. -It generally does not make sense to use this in production. - -### SimplePolicy - -Restricts the visibility of posts from certain instances. - - config :pleroma, :mrf_simple, - media_removal: [], - media_nsfw: [], - federated_timeline_removal: [], - reject: [], - accept: [] - -* `media_removal`: posts from these instances will have attachments - removed -* `media_nsfw`: posts from these instances will have attachments marked - as nsfw -* `federated_timeline_removal`: posts from these instances will be - marked as unlisted -* `reject`: posts from these instances will be dropped -* `accept`: if not empty, only posts from these instances will be accepted - -### RejectNonPublic - -Drops posts with non-public visibility settings. - - config :pleroma :mrf_rejectnonpublic - allow_followersonly: false, - allow_direct: false, - -* `allow_followersonly`: whether to allow follower-only posts through - the filter -* `allow_direct`: whether to allow direct messages through the filter diff --git a/README.md b/README.md index 3523c9a92..642d3e954 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ While we don't provide docker files, other people have written very good ones. T * Run `mix generate_config`. This will ask you a few questions about your instance and generate a configuration file in `config/generated_config.exs`. Check that and copy it to either `config/dev.secret.exs` or `config/prod.secret.exs`. It will also create a `config/setup_db.psql`; you may want to double-check this file in case you wanted a different username, or database name than the default. Then you need to run the script as PostgreSQL superuser (i.e. `sudo su postgres -c "psql -f config/setup_db.psql"`). It will create a pleroma db user, database and will setup needed extensions that need to be set up. Postgresql super-user privileges are only needed for this step. - * For these next steps, the default will be to run pleroma using the dev configuration file, `config/dev.secret.exs`. To run them using the prod config file, prefix each command at the shell with `MIX_ENV=prod`. For example: `MIX_ENV=prod mix phx.server`. + * For these next steps, the default will be to run pleroma using the dev configuration file, `config/dev.secret.exs`. To run them using the prod config file, prefix each command at the shell with `MIX_ENV=prod`. For example: `MIX_ENV=prod mix phx.server`. Documentation for the config can be found at [``config/config.md``](config/config.md) * Run `mix ecto.migrate` to run the database migrations. You will have to do this again after certain updates. @@ -45,8 +45,6 @@ While we don't provide docker files, other people have written very good ones. T * The common and convenient way for adding HTTPS is by using Nginx as a reverse proxy. You can look at example Nginx configuration in `installation/pleroma.nginx`. If you need TLS/SSL certificates for HTTPS, you can look get some for free with letsencrypt: https://letsencrypt.org/ The simplest way to obtain and install a certificate is to use [Certbot.](https://certbot.eff.org) Depending on your specific setup, certbot may be able to get a certificate and configure your web server automatically. - * [Not tested with system reboot yet!] You'll also want to set up Pleroma to be run as a systemd service. Example .service file can be found in `installation/pleroma.service` you can put it in `/etc/systemd/system/`. - ## Running * By default, it listens on port 4000 (TCP), so you can access it on http://localhost:4000/ (if you are on the same machine). In case of an error it will restart automatically. @@ -55,9 +53,15 @@ While we don't provide docker files, other people have written very good ones. T Pleroma comes with two frontends. The first one, Pleroma FE, can be reached by normally visiting the site. The other one, based on the Mastodon project, can be found by visiting the /web path of your site. ### As systemd service (with provided .service file) +Example .service file can be found in `installation/pleroma.service` you can put it in `/etc/systemd/system/`. Running `service pleroma start` Logs can be watched by using `journalctl -fu pleroma.service` +### As OpenRC service (with provided RC file) +Copy ``installation/init.d/pleroma`` to ``/etc/init.d/pleroma``. +You can add it to the services ran by default with: +``rc-update add pleroma`` + ### Standalone/run by other means Run `mix phx.server` in repository's root, it will output log into stdout/stderr @@ -70,22 +74,6 @@ Add the following to your `dev.secret.exs` or `prod.secret.exs` if you want to p This is useful for running pleroma inside Tor or i2p. -## Admin Tasks - -### Register a User - -Run `mix register_user `. The `name` appears on statuses, while the nickname corresponds to the user, e.g. `@nickname@instance.tld` - -### Password reset - -Run `mix generate_password_reset username` to generate a password reset link that you can then send to the user. - -### Moderators - -You can make users moderators. They will then be able to delete any post. - -Run `mix set_moderator username [true|false]` to make user a moderator or not. - ## Troubleshooting ### No incoming federation diff --git a/config/config.md b/config/config.md new file mode 100644 index 000000000..51172fc4d --- /dev/null +++ b/config/config.md @@ -0,0 +1,82 @@ +# Configuration + +This file describe the configuration, it is recommended to edit the relevant *.secret.exs file instead of the others founds in the ``config`` directory. +If you run Pleroma with ``MIX_ENV=prod`` the file is ``prod.secret.exs``, otherwise it is ``dev.secret.exs``. + +## Pleroma.Upload +* `uploader`: Select which `Pleroma.Uploaders` to use +* `strip_exif`: boolean, uses ImageMagick(!) to strip exif. + +## Pleroma.Uploaders.Local +* `uploads`: Which directory to store the user-uploads in, relative to pleroma’s working directory +* `uploads_url`: The URL to access a user-uploaded file, ``{{base_url}}`` is replaced to the instance URL and ``{{file}}`` to the filename. Useful when you want to proxy the media files via another host. + +## :uri_schemes +* `valid_schemes`: List of the scheme part that is considered valid to be an URL + +## :instance +* `name`: The instance’s name +* `email`: Email used to reach an Administrator/Moderator of the instance +* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance`` +* `limit`: Posts character limit (CW/Subject included in the counter) +* `upload_limit`: File size limit of uploads (except for avatar, background, banner) +* `avatar_upload_limit`: File size limit of user’s profile avatars +* `background_upload_limit`: File size limit of user’s profile backgrounds +* `banner_upload_limit`: File size limit of user’s profile backgrounds +* `registerations_open`: Enable registerations for anyone, invitations can be used when false. +* `federating` +* `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance +* `rewrite_policy`: Message Rewrite Policy, either one or a list. Here are the ones available by default: + * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default) + * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production + * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See ``:mrf_simple`` section) + * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See ``:mrf_rejectnonpublic`` section) +* `public`: Makes the client API in authentificated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. +* `quarantined_instances`: List of ActivityPub instances where private(DMs, followers-only) activities will not be send. +* `managed_config`: Whenether the config for pleroma-fe is configured in this config or in ``static/config.json`` +* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML) +* `finmoji_enabled`: Whenether to enable the finmojis in the custom emojis. +* `mrf_transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). + +## :fe +This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:instance`` is set to false. + +* `theme`: Which theme to use, they are defined in ``styles.json`` +* `logo`: URL of the logo, defaults to Pleroma’s logo +* `logo_mask`: Whenether to mask the logo +* `logo_margin`: What margin to use around the logo +* `background`: URL of the background, unless viewing a user profile with a background that is set +* `redirect_root_no_login`: relative URL which indicates where to redirect when a user isn’t logged in. +* `redirect_root_login`: relative URL which indicates where to redirect when a user is logged in. +* `show_instance_panel`: Whenether to show the instance’s specific panel. +* `scope_options_enabled`: Enable setting an notice visibility and subject/CW when posting +* `formatting_options_enabled`: Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to ``:instance, allowed_post_formats`` +* `collapse_message_with_subjects`: When a message has a subject(aka Content Warning), collapse it by default +* `hide_post_stats`: Hide notices statistics(repeats, favorites, …) +* `hide_user_stats`: Hide profile statistics(posts, posts per day, followers, followings, …) + +## :mrf_simple +* `media_removal`: List of instances to remove medias from +* `media_nsfw`: List of instances to put medias as NSFW(sensitive) from +* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline +* `reject`: List of instances to reject any activities from +* `accept`: List of instances to accept any activities from + +## :mrf_rejectnonpublic +* `allow_followersonly`: whether to allow followers-only posts +* `allow_direct`: whether to allow direct messages + +## :media_proxy +* `enabled`: Enables proxying of remote media to the instance’s proxy +* `redirect_on_failure`: Use the original URL when Media Proxy fails to get it + +## :gopher +* `enabled`: Enables the gopher interface +* `ip`: IP address to bind to +* `port`: Port to bind to + +## :activitypub +* ``accept_blocks``: Whether to accept incoming block activities from other instances +* ``unfollow_blocked``: Whether blocks result in people getting unfollowed +* ``outgoing_blocks``: Whether to federate blocks to other instances +* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question diff --git a/lib/mix/tasks/deactivate_user.ex b/lib/mix/tasks/deactivate_user.ex index f18541787..e71ed1ec0 100644 --- a/lib/mix/tasks/deactivate_user.ex +++ b/lib/mix/tasks/deactivate_user.ex @@ -2,7 +2,13 @@ defmodule Mix.Tasks.DeactivateUser do use Mix.Task alias Pleroma.User - @shortdoc "Deactivate a user" + @moduledoc """ + Deactivates a user (local or remote) + + Usage: ``mix deactivate_user `` + + Example: ``mix deactivate_user lain`` + """ def run([nickname]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/generate_config.ex b/lib/mix/tasks/generate_config.ex index 70a110561..e3cbbf131 100644 --- a/lib/mix/tasks/generate_config.ex +++ b/lib/mix/tasks/generate_config.ex @@ -1,7 +1,15 @@ defmodule Mix.Tasks.GenerateConfig do use Mix.Task - @shortdoc "Generates a new config" + @moduledoc """ + Generate a new config + + ## Usage + ``mix generate_config`` + + This mix task is interactive, and will overwrite the config present at ``config/generated_config.exs``. + """ + def run(_) do IO.puts("Answer a few questions to generate a new config\n") IO.puts("--- THIS WILL OVERWRITE YOUR config/generated_config.exs! ---\n") diff --git a/lib/mix/tasks/generate_invite_token.ex b/lib/mix/tasks/generate_invite_token.ex index c4daa9a6c..418ef3790 100644 --- a/lib/mix/tasks/generate_invite_token.ex +++ b/lib/mix/tasks/generate_invite_token.ex @@ -1,7 +1,14 @@ defmodule Mix.Tasks.GenerateInviteToken do use Mix.Task - @shortdoc "Generate invite token for user" + @moduledoc """ + Generates invite token + + This is in the form of a URL to be used by the Invited user to register themselves. + + ## Usage + ``mix generate_invite_token`` + """ def run([]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/generate_password_reset.ex b/lib/mix/tasks/generate_password_reset.ex index 6bf640150..f7f4c4f59 100644 --- a/lib/mix/tasks/generate_password_reset.ex +++ b/lib/mix/tasks/generate_password_reset.ex @@ -2,7 +2,13 @@ defmodule Mix.Tasks.GeneratePasswordReset do use Mix.Task alias Pleroma.User - @shortdoc "Generate password reset link for user" + @moduledoc """ + Generate password reset link for user + + Usage: ``mix generate_password_reset `` + + Example: ``mix generate_password_reset lain`` + """ def run([nickname]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/make_moderator.ex b/lib/mix/tasks/make_moderator.ex index a454a958e..15586dc30 100644 --- a/lib/mix/tasks/make_moderator.ex +++ b/lib/mix/tasks/make_moderator.ex @@ -1,9 +1,16 @@ defmodule Mix.Tasks.SetModerator do + @moduledoc """ + Set moderator to a local user + + Usage: ``mix set_moderator `` + + Example: ``mix set_moderator lain`` + """ + use Mix.Task import Mix.Ecto alias Pleroma.{Repo, User} - @shortdoc "Set moderator status" def run([nickname | rest]) do Application.ensure_all_started(:pleroma) diff --git a/lib/mix/tasks/reactivate_user.ex b/lib/mix/tasks/reactivate_user.ex index 40bd068ea..a30d3ac8b 100644 --- a/lib/mix/tasks/reactivate_user.ex +++ b/lib/mix/tasks/reactivate_user.ex @@ -2,7 +2,13 @@ defmodule Mix.Tasks.ReactivateUser do use Mix.Task alias Pleroma.User - @shortdoc "Reactivate a user" + @moduledoc """ + Reactivate a user + + Usage: ``mix reactivate_user `` + + Example: ``mix reactivate_user lain`` + """ def run([nickname]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/register_user.ex b/lib/mix/tasks/register_user.ex index e74721c49..1f5321093 100644 --- a/lib/mix/tasks/register_user.ex +++ b/lib/mix/tasks/register_user.ex @@ -1,4 +1,12 @@ defmodule Mix.Tasks.RegisterUser do + @moduledoc """ + Manually register a local user + + Usage: ``mix register_user `` + + Example: ``mix register_user 仮面の告白 lain lain@example.org "blushy-crushy fediverse idol + pleroma dev" pleaseDontHeckLain`` + """ + use Mix.Task alias Pleroma.{Repo, User} diff --git a/lib/mix/tasks/relay_follow.ex b/lib/mix/tasks/relay_follow.ex index ac6f20924..4d57c6bca 100644 --- a/lib/mix/tasks/relay_follow.ex +++ b/lib/mix/tasks/relay_follow.ex @@ -4,6 +4,13 @@ defmodule Mix.Tasks.RelayFollow do alias Pleroma.Web.ActivityPub.Relay @shortdoc "Follows a remote relay" + @moduledoc """ + Follows a remote relay + + Usage: ``mix relay_follow `` + + Example: ``mix relay_follow https://example.org/relay`` + """ def run([target]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/relay_unfollow.ex b/lib/mix/tasks/relay_unfollow.ex index 4621ace83..bd69fd8a0 100644 --- a/lib/mix/tasks/relay_unfollow.ex +++ b/lib/mix/tasks/relay_unfollow.ex @@ -3,7 +3,13 @@ defmodule Mix.Tasks.RelayUnfollow do require Logger alias Pleroma.Web.ActivityPub.Relay - @shortdoc "Follows a remote relay" + @moduledoc """ + Unfollows a remote relay + + Usage: ``mix relay_follow `` + + Example: ``mix relay_follow https://example.org/relay`` + """ def run([target]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/rm_user.ex b/lib/mix/tasks/rm_user.ex index b7c922d6c..50463046c 100644 --- a/lib/mix/tasks/rm_user.ex +++ b/lib/mix/tasks/rm_user.ex @@ -2,7 +2,13 @@ defmodule Mix.Tasks.RmUser do use Mix.Task alias Pleroma.User - @shortdoc "Permanently delete a user" + @moduledoc """ + Permanently deletes a user + + Usage: ``mix rm_user [nickname]`` + + Example: ``mix rm_user lain`` + """ def run([nickname]) do Mix.Task.run("app.start") diff --git a/lib/mix/tasks/set_locked.ex b/lib/mix/tasks/set_locked.ex index 2b3b18b09..a154595ca 100644 --- a/lib/mix/tasks/set_locked.ex +++ b/lib/mix/tasks/set_locked.ex @@ -1,9 +1,18 @@ defmodule Mix.Tasks.SetLocked do + @moduledoc """ + Lock a local user + + The local user will then have to manually accept/reject followers. This can also be done by the user into their settings. + + Usage: ``mix set_locked `` + + Example: ``mix set_locked lain`` + """ + use Mix.Task import Mix.Ecto alias Pleroma.{Repo, User} - @shortdoc "Set locked status" def run([nickname | rest]) do ensure_started(Repo, []) diff --git a/lib/mix/tasks/unsubscribe_user.ex b/lib/mix/tasks/unsubscribe_user.ex index bb72634b6..62ea61a5c 100644 --- a/lib/mix/tasks/unsubscribe_user.ex +++ b/lib/mix/tasks/unsubscribe_user.ex @@ -3,7 +3,13 @@ defmodule Mix.Tasks.UnsubscribeUser do alias Pleroma.{User, Repo} require Logger - @shortdoc "Unsubscribe all users from a target and then deactivate them" + @moduledoc """ + Deactivate and Unsubscribe local users from a user + + Usage: ``mix unsubscribe_user `` + + Example: ``mix unsubscribe_user lain`` + """ def run([nickname]) do Mix.Task.run("app.start") diff --git a/mix.exs b/mix.exs index 427c5d810..ded414da9 100644 --- a/mix.exs +++ b/mix.exs @@ -10,7 +10,19 @@ def project do compilers: [:phoenix, :gettext] ++ Mix.compilers(), start_permanent: Mix.env() == :prod, aliases: aliases(), - deps: deps() + deps: deps(), + + # Docs + name: "Pleroma", + source_url: "https://git.pleroma.social/pleroma/pleroma", + source_url_pattern: + "https://git.pleroma.social/pleroma/pleroma/blob/develop/%{path}#L%{line}", + homepage_url: "https://pleroma.social/", + docs: [ + logo: "priv/static/static/logo.png", + extras: ["README.md", "config/config.md"], + main: "readme" + ] ] end @@ -54,7 +66,8 @@ defp deps do {:mock, "~> 0.3.1", only: :test}, {:crypt, git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"}, - {:cors_plug, "~> 1.5"} + {:cors_plug, "~> 1.5"}, + {:ex_doc, "> 0.18.3 and < 0.20.0", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index 13ccbd251..c0fa892a5 100644 --- a/mix.lock +++ b/mix.lock @@ -24,6 +24,7 @@ "httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "5.1.2", "e21cb58a09f0228a9e0b95eaa1217f1bcfc31a1aaa6e1fdf2f53a33f7dbd9494", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, + "makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "meck": {:hex, :meck, "0.8.9", "64c5c0bd8bcca3a180b44196265c8ed7594e16bcc845d0698ec6b4e577f48188", [:rebar3], [], "hexpm"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"}, @@ -31,6 +32,7 @@ "mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [:rebar3], [], "hexpm"}, "mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.3.4", "aaa1b55e5523083a877bcbe9886d9ee180bf2c8754905323493c2ac325903dc5", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},