A generic OpenID Connect implementation (#413)

* Add ueberauth_oidc as dependency

* Update OIDC dependency

Todo: Figure out why the Hex.io one didn't work

* Begin OIDC implementation

* It.. actually works???

* Minor changes

* Change french so it hopefully fits better

* Update mix.lock

* Break everything, but shall continue on other machine

* Add OIDC environment variables to README

* Check for OIDC client ID before adding OpenID Worker

* Add fancy icon

* Remove comments

* Fix formatting

* Fix formatting... again.

* Change back to hex.io's ueberauth_oidc
This commit is contained in:
dynamyc 2024-03-03 21:11:43 +01:00 committed by GitHub
parent d8e3a70991
commit bfd259e05c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 263 additions and 18 deletions

View File

@ -139,24 +139,29 @@ Accent provides a default value for every required environment variable. This me
Various login providers are included in Accent using Ueberauth to abstract services.
| Variable | Default | Description |
| -------------------------- | -------------------- | --------------------------------------------------------------------------------------- |
| `DUMMY_LOGIN_ENABLED` | _none_ | If specified, the password-less authentication (with only the email) will be available. |
| `GITHUB_CLIENT_ID` | _none_ | |
| `GITHUB_CLIENT_SECRET` | _none_ | |
| `GITLAB_CLIENT_ID` | _none_ | |
| `GITLAB_CLIENT_SECRET` | _none_ | |
| `GITLAB_SITE_URL` | `https://gitlab.com` | |
| `GOOGLE_API_CLIENT_ID` | _none_ | |
| `GOOGLE_API_CLIENT_SECRET` | _none_ | |
| `SLACK_CLIENT_ID` | _none_ | |
| `SLACK_CLIENT_SECRET` | _none_ | |
| `SLACK_TEAM_ID` | _none_ | |
| `DISCORD_CLIENT_ID` | _none_ | |
| `DISCORD_CLIENT_SECRET` | _none_ | |
| `MICROSOFT_CLIENT_ID` | _none_ | |
| `MICROSOFT_CLIENT_SECRET` | _none_ | |
| `MICROSOFT_TENANT_ID` | _none_ | |
| Variable | Default | Description |
| -------------------------- | ---------------------- | --------------------------------------------------------------------------------------- |
| `DUMMY_LOGIN_ENABLED` | _none_ | If specified, the password-less authentication (with only the email) will be available. |
| `GITHUB_CLIENT_ID` | _none_ | |
| `GITHUB_CLIENT_SECRET` | _none_ | |
| `GITLAB_CLIENT_ID` | _none_ | |
| `GITLAB_CLIENT_SECRET` | _none_ | |
| `GITLAB_SITE_URL` | `https://gitlab.com` | |
| `GOOGLE_API_CLIENT_ID` | _none_ | |
| `GOOGLE_API_CLIENT_SECRET` | _none_ | |
| `SLACK_CLIENT_ID` | _none_ | |
| `SLACK_CLIENT_SECRET` | _none_ | |
| `SLACK_TEAM_ID` | _none_ | |
| `DISCORD_CLIENT_ID` | _none_ | |
| `DISCORD_CLIENT_SECRET` | _none_ | |
| `MICROSOFT_CLIENT_ID` | _none_ | |
| `MICROSOFT_CLIENT_SECRET` | _none_ | |
| `MICROSOFT_TENANT_ID` | _none_ | |
| `OIDC_CLIENT_ID` | _none_ | |
| `OIDC_CLIENT_SECRET` | _none_ | |
| `OIDC_DISCOVERY_URI` | _none_ | |
| `OIDC_UID_FIELD` | `sub` | |
| `OIDC_SCOPE` | `openid profile email` | |
### Email setup

View File

@ -88,6 +88,11 @@ providers =
providers = if get_env("AUTH0_CLIENT_ID"), do: [{:auth0, {Ueberauth.Strategy.Auth0, []}} | providers], else: providers
providers =
if get_env("OIDC_CLIENT_ID"),
do: [{:oidc, {Ueberauth.Strategy.OIDC, [default: [provider: :default_oidc, uid_field: :sub]]}} | providers],
else: providers
providers =
if get_env("DUMMY_LOGIN_ENABLED"),
do: [{:dummy, {Accent.Auth.Ueberauth.DummyStrategy, []}} | providers],
@ -129,6 +134,18 @@ config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth,
client_secret: get_env("MICROSOFT_CLIENT_SECRET"),
tenant_id: get_env("MICROSOFT_TENANT_ID")
config :ueberauth, Ueberauth.Strategy.OIDC,
default_oidc: [
fetch_userinfo: true,
uid_field: get_env("OIDC_UID_FIELD") || "sub",
client_id: get_env("OIDC_CLIENT_ID"),
client_secret: get_env("OIDC_CLIENT_SECRET"),
discovery_document_uri: get_env("OIDC_DISCOVERY_URI"),
redirect_uri: "#{static_uri}/auth/oidc/callback",
response_type: "code",
scope: get_env("OIDC_SCOPE") || "openid profile email"
]
config :accent, Accent.WebappView,
path: "priv/static/webapp/index.html",
sentry_dsn: get_env("WEBAPP_SENTRY_DSN") || "",

View File

@ -16,6 +16,11 @@ defmodule Accent do
{Phoenix.PubSub, [name: Accent.PubSub, adapter: Phoenix.PubSub.PG2]}
]
children =
if Application.get_env(:ueberauth, Ueberauth.Strategy.OIDC)[:default_oidc][:client_id],
do: [{OpenIDConnect.Worker, Application.get_env(:ueberauth, Ueberauth.Strategy.OIDC)} | children],
else: children
if Application.get_env(:sentry, :dsn) do
{:ok, _} = Logger.add_backend(Sentry.LoggerBackend)
end

View File

@ -91,6 +91,7 @@ defmodule Accent.Mixfile do
{:ueberauth_github, "~> 0.7"},
{:ueberauth_discord, "~> 0.5"},
{:ueberauth_auth0, "~> 2.0"},
{:ueberauth_oidc, "~> 0.1.7"},
# Errors
{:sentry, "~> 7.0"},

View File

@ -62,6 +62,7 @@
"nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"},
"oauth2": {:hex, :oauth2, "2.1.0", "beb657f393814a3a7a8a15bd5e5776ecae341fd344df425342a3b6f1904c2989", [:mix], [{:tesla, "~> 1.5", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "8ac07f85b3307dd1acfeb0ec852f64161b22f57d0ce0c15e616a1dfc8ebe2b41"},
"oban": {:hex, :oban, "2.17.3", "ddfd5710aadcd550d2e174c8d73ce5f1865601418cf54a91775f20443fb832b7", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "452eada8bfe0d0fefd0740ab5fa8cf3ef6c375df0b4a3c3805d179022a04738a"},
"openid_connect": {:hex, :openid_connect, "0.2.2", "c05055363330deab39ffd89e609db6b37752f255a93802006d83b45596189c0b", [:mix], [{:httpoison, "~> 1.2", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "735769b6d592124b58edd0582554ce638524c0214cd783d8903d33357d74cc13"},
"p1_utils": {:hex, :p1_utils, "1.0.15", "731f76ae1f31f4554afb2ae629cb5589d53bd13efc72b11f5a7c3b1242f91046", [:rebar3], [], "hexpm", "1d308c3f37d7f770fb39abe3b86701b82d54414bc2499d9499edde3cb50bcf19"},
"parallel_stream": {:hex, :parallel_stream, "1.1.0", "f52f73eb344bc22de335992377413138405796e0d0ad99d995d9977ac29f1ca9", [:mix], [], "hexpm", "684fd19191aedfaf387bbabbeb8ff3c752f0220c8112eb907d797f4592d6e871"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
@ -103,6 +104,7 @@
"ueberauth_github": {:hex, :ueberauth_github, "0.8.3", "1c478629b4c1dae446c68834b69194ad5cead3b6c67c913db6fdf64f37f0328f", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "ae0ab2879c32cfa51d7287a48219b262bfdab0b7ec6629f24160564247493cc6"},
"ueberauth_google": {:hex, :ueberauth_google, "0.12.1", "90cf49743588193334f7a00da252f92d90bfd178d766c0e4291361681fafec7d", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.10.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "7f7deacd679b2b66e3bffb68ecc77aa1b5396a0cbac2941815f253128e458c38"},
"ueberauth_microsoft": {:hex, :ueberauth_microsoft, "0.23.0", "5c78e02a83d821ee45f96216bb6140ba688cc79b8b26e7ff438e3abe24615e1d", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "0c08d98203e6d3069f30306f09a6cb55b95c2bda94d6f8e90f05bd442ee96b82"},
"ueberauth_oidc": {:git, "https://github.com/DefactoSoftware/ueberauth_oidc.git", "0e46efb1214d848256f2cdfa394b80448a06c9a4", []},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
"vega_lite": {:hex, :vega_lite, "0.1.8", "7f6119126ecaf4bc2c1854084370d7091424f5cce4795fbac044eee9963f0752", [:mix], [{:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "6c8a9271f850612dd8a90de8d1ebd433590ed07ffef76fc2397c240dc04d3fdc"},

View File

@ -21,6 +21,7 @@ export default class LoginForms extends Component<Args> {
discordUrl = `${config.API.AUTHENTICATION_PATH}/discord`;
microsoftUrl = `${config.API.AUTHENTICATION_PATH}/microsoft`;
auth0Url = `${config.API.AUTHENTICATION_PATH}/auth0`;
oidcUrl = `${config.API.AUTHENTICATION_PATH}/oidc`;
get version() {
return config.version === '__VERSION__' ? 'dev' : config.version;
@ -62,6 +63,10 @@ export default class LoginForms extends Component<Args> {
return this.providerIds.includes('microsoft');
}
get oidcLoginEnabled() {
return this.providerIds.includes('oidc');
}
get dummyUrl() {
return `${config.API.AUTHENTICATION_PATH}/dummy/callback?email=${this.username}`;
}

View File

@ -62,6 +62,7 @@
"slack": "Login with Slack →",
"discord": "Login with Discord →",
"microsoft": "Login with Microsoft →",
"oidc": "Login with OpenID Connect →",
"dummy": "Enter an email and login →"
},
"dummy_login_form": {

View File

@ -78,6 +78,7 @@
"slack": "Se connecter avec Slack →",
"discord": "Se connecter avec Discord →",
"microsoft": "Se connecter avec Microsoft →",
"oidc": "Connectez-vous avec OIDC →",
"dummy": "Entrez un courriel et connectez-vous →"
},
"dummy_login_form": {

View File

@ -218,6 +218,13 @@ a.loginButton {
color: #03a5f0;
background: lighten(#03a5f0, 48%);
}
&.loginButton--oidc {
border-color: #f7931e;
text-shadow: none;
color: #f7931e;
background: lighten(#f7931e, 48%);
}
}
.loginButton-logo {

View File

@ -92,6 +92,13 @@
{{t 'components.login_forms.auth0'}}
</a>
{{/if}}
{{#if this.oidcLoginEnabled}}
<a href={{this.oidcUrl}} class='button button--filled' local-class='loginButton loginButton--oidc'>
<img src='assets/auth_providers/oidc.svg' local-class='loginButton-logo' />
{{t 'components.login_forms.oidc'}}
</a>
{{/if}}
{{/if}}
</div>
</div>

View File

@ -0,0 +1,194 @@
<svg
version="1.1"
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
width="100%"
viewBox="0 0 1000 1000"
enable-background="new 0 0 1000 1000"
xml:space="preserve"
>
<path
fill="#000000"
opacity="0.000000"
stroke="none"
d="
M466.000000,1001.000000
C310.666656,1001.000000 155.833328,1001.000000 1.000000,1001.000000
C1.000000,667.666687 1.000000,334.333344 1.000000,1.000000
C334.333344,1.000000 667.666687,1.000000 1001.000000,1.000000
C1001.000000,334.333344 1001.000000,667.666687 1001.000000,1001.000000
C822.833313,1001.000000 644.666687,1001.000000 466.000000,1001.000000
M455.943146,959.999817
C462.778870,957.052063 469.692017,954.270508 476.436768,951.127625
C505.034454,937.801636 533.591736,924.388794 562.143738,910.965027
C575.098694,904.874207 587.842896,898.294983 601.021912,892.742188
C605.882690,890.694153 607.113342,888.409546 607.111084,883.435913
C606.986145,604.831299 607.000000,326.226654 607.000000,47.622002
C607.000000,45.639111 607.000000,43.656219 607.000000,41.293358
C602.127625,43.453136 597.487915,45.356312 592.980469,47.533421
C568.492004,59.361439 544.016724,71.217171 519.575256,83.141922
C499.803711,92.788277 480.148407,102.675789 460.295227,112.149742
C456.065857,114.168007 454.897461,116.653015 454.899567,121.176468
C455.012939,366.955048 455.000427,612.733704 454.993103,858.512329
C454.993042,860.674805 454.889191,862.837280 453.977783,864.999878
C445.455353,863.670959 436.936798,862.316467 428.409729,861.017944
C404.637177,857.397827 381.446747,851.370422 358.531219,844.192566
C327.460022,834.460022 297.776123,821.535522 269.782196,804.913696
C245.658417,790.589783 223.477463,773.806396 204.363281,753.016785
C189.329025,736.664490 176.755936,718.906555 167.743011,698.524719
C160.900726,683.051514 156.289597,666.964478 155.271057,650.240906
C154.544571,638.312744 155.620895,626.141174 157.142914,614.238098
C160.099564,591.114990 169.845428,570.356201 182.557800,551.185974
C196.108139,530.752197 213.387131,513.565430 232.371124,498.048279
C249.579697,483.982269 268.245758,472.168030 287.977570,462.132416
C301.402771,455.304382 315.211182,449.131165 329.184357,443.499084
C361.582825,430.440491 395.191437,421.522034 429.586182,415.634003
C429.586182,383.427063 429.586182,351.266876 429.586182,319.362366
C426.258636,319.603668 423.297302,319.592865 420.415039,320.064972
C404.681519,322.641876 388.828461,324.707428 373.278412,328.136444
C348.456879,333.609924 323.676300,339.419708 299.180450,346.181519
C269.029755,354.504333 239.892563,365.879578 211.596329,379.195923
C183.186798,392.565552 155.548172,407.524353 130.435883,426.448303
C113.310898,439.353241 97.007431,453.426056 81.049934,467.770172
C72.910034,475.087128 66.180939,484.017242 59.094452,492.453644
C42.886402,511.749237 29.845125,532.992920 19.915037,556.200256
C10.222878,578.851624 4.147080,602.467957 3.298953,626.963440
C2.737377,643.182800 3.633550,659.735840 6.334104,675.724487
C11.524273,706.452942 23.881523,734.688354 41.188843,760.597046
C54.976284,781.236572 70.421402,800.579285 89.370407,816.801758
C103.183212,828.626953 116.701233,840.932068 131.429031,851.523804
C159.178391,871.480286 189.176254,887.719788 220.343689,901.797363
C249.764328,915.085876 280.090424,925.895264 311.168610,934.447815
C330.054321,939.644958 349.215820,943.944824 368.410461,947.882263
C384.499603,951.182678 400.775085,953.666077 417.045502,955.962219
C429.690643,957.746765 442.455078,958.685486 455.943146,959.999817
M927.017395,563.519836
C950.873535,568.661987 974.729675,573.804138 998.998474,579.035278
C998.998474,577.600464 999.076660,576.610718 998.986450,575.636536
C998.003357,565.023804 996.993530,554.413513 995.992004,543.802490
C995.313538,536.614746 994.706360,529.419556 993.943848,522.240784
C992.681763,510.358459 991.212280,498.497375 990.036194,486.606964
C989.178650,477.937164 988.806702,469.219269 987.944885,460.549988
C986.405823,445.067780 984.548767,429.616913 983.036621,414.132294
C981.855286,402.034393 981.078552,389.897369 979.951111,377.793671
C979.491760,372.861908 978.580688,367.972168 977.761169,362.270630
C967.561096,368.043396 958.117737,373.396698 948.665955,378.735077
C933.404907,387.354492 918.163574,396.009857 902.825500,404.489929
C901.614441,405.159485 899.411377,405.147705 898.184143,404.490784
C891.320312,400.816742 884.738464,396.608856 877.832642,393.021698
C855.213135,381.272186 832.384583,369.904114 808.190674,361.705414
C785.984375,354.180328 763.798279,346.463043 741.224365,340.195343
C721.724121,334.781067 701.753052,330.972626 681.874451,327.039093
C665.498108,323.798584 648.952148,321.415039 632.233276,318.610046
C632.233276,351.488434 632.233276,383.591400 632.233276,415.589111
C686.855652,425.100861 738.748352,441.672028 787.312012,469.290710
C773.387756,477.084106 759.957153,484.572784 746.554382,492.110870
C733.251587,499.592712 719.976746,507.124329 705.474487,515.320984
C716.430603,517.795471 725.715332,519.956848 735.029602,521.982361
C753.096802,525.911377 771.184692,529.745056 789.256287,533.654114
C803.522278,536.739990 817.771606,539.903076 832.037476,542.989746
C850.108826,546.899841 868.184631,550.789185 886.267517,554.645569
C899.597717,557.488342 912.942139,560.263977 927.017395,563.519836
z"
/>
<path
fill="#F7931E"
opacity="1.000000"
stroke="none"
d="
M454.833771,864.999756
C454.889191,862.837280 454.993042,860.674805 454.993103,858.512329
C455.000427,612.733704 455.012939,366.955048 454.899567,121.176468
C454.897461,116.653015 456.065857,114.168007 460.295227,112.149742
C480.148407,102.675789 499.803711,92.788277 519.575256,83.141922
C544.016724,71.217171 568.492004,59.361439 592.980469,47.533421
C597.487915,45.356312 602.127625,43.453136 607.000000,41.293358
C607.000000,43.656219 607.000000,45.639111 607.000000,47.622002
C607.000000,326.226654 606.986145,604.831299 607.111084,883.435913
C607.113342,888.409546 605.882690,890.694153 601.021912,892.742188
C587.842896,898.294983 575.098694,904.874207 562.143738,910.965027
C533.591736,924.388794 505.034454,937.801636 476.436768,951.127625
C469.692017,954.270508 462.778870,957.052063 455.495209,959.535278
C455.031525,955.752441 455.007996,952.434204 455.001160,949.115906
C454.943604,921.077209 454.889191,893.038452 454.833771,864.999756
z"
/>
<path
fill="#B2B2B2"
opacity="1.000000"
stroke="none"
d="
M454.405762,864.999817
C454.889191,893.038452 454.943604,921.077209 455.001160,949.115906
C455.007996,952.434204 455.031525,955.752441 455.106873,959.535400
C442.455078,958.685486 429.690643,957.746765 417.045502,955.962219
C400.775085,953.666077 384.499603,951.182678 368.410461,947.882263
C349.215820,943.944824 330.054321,939.644958 311.168610,934.447815
C280.090424,925.895264 249.764328,915.085876 220.343689,901.797363
C189.176254,887.719788 159.178391,871.480286 131.429031,851.523804
C116.701233,840.932068 103.183212,828.626953 89.370407,816.801758
C70.421402,800.579285 54.976284,781.236572 41.188843,760.597046
C23.881523,734.688354 11.524273,706.452942 6.334104,675.724487
C3.633550,659.735840 2.737377,643.182800 3.298953,626.963440
C4.147080,602.467957 10.222878,578.851624 19.915037,556.200256
C29.845125,532.992920 42.886402,511.749237 59.094452,492.453644
C66.180939,484.017242 72.910034,475.087128 81.049934,467.770172
C97.007431,453.426056 113.310898,439.353241 130.435883,426.448303
C155.548172,407.524353 183.186798,392.565552 211.596329,379.195923
C239.892563,365.879578 269.029755,354.504333 299.180450,346.181519
C323.676300,339.419708 348.456879,333.609924 373.278412,328.136444
C388.828461,324.707428 404.681519,322.641876 420.415039,320.064972
C423.297302,319.592865 426.258636,319.603668 429.586182,319.362366
C429.586182,351.266876 429.586182,383.427063 429.586182,415.634003
C395.191437,421.522034 361.582825,430.440491 329.184357,443.499084
C315.211182,449.131165 301.402771,455.304382 287.977570,462.132416
C268.245758,472.168030 249.579697,483.982269 232.371124,498.048279
C213.387131,513.565430 196.108139,530.752197 182.557800,551.185974
C169.845428,570.356201 160.099564,591.114990 157.142914,614.238098
C155.620895,626.141174 154.544571,638.312744 155.271057,650.240906
C156.289597,666.964478 160.900726,683.051514 167.743011,698.524719
C176.755936,718.906555 189.329025,736.664490 204.363281,753.016785
C223.477463,773.806396 245.658417,790.589783 269.782196,804.913696
C297.776123,821.535522 327.460022,834.460022 358.531219,844.192566
C381.446747,851.370422 404.637177,857.397827 428.409729,861.017944
C436.936798,862.316467 445.455353,863.670959 454.405762,864.999817
z"
/>
<path
fill="#B2B2B2"
opacity="1.000000"
stroke="none"
d="
M926.648804,563.294678
C912.942139,560.263977 899.597717,557.488342 886.267517,554.645569
C868.184631,550.789185 850.108826,546.899841 832.037476,542.989746
C817.771606,539.903076 803.522278,536.739990 789.256287,533.654114
C771.184692,529.745056 753.096802,525.911377 735.029602,521.982361
C725.715332,519.956848 716.430603,517.795471 705.474487,515.320984
C719.976746,507.124329 733.251587,499.592712 746.554382,492.110870
C759.957153,484.572784 773.387756,477.084106 787.312012,469.290710
C738.748352,441.672028 686.855652,425.100861 632.233276,415.589111
C632.233276,383.591400 632.233276,351.488434 632.233276,318.610046
C648.952148,321.415039 665.498108,323.798584 681.874451,327.039093
C701.753052,330.972626 721.724121,334.781067 741.224365,340.195343
C763.798279,346.463043 785.984375,354.180328 808.190674,361.705414
C832.384583,369.904114 855.213135,381.272186 877.832642,393.021698
C884.738464,396.608856 891.320312,400.816742 898.184143,404.490784
C899.411377,405.147705 901.614441,405.159485 902.825500,404.489929
C918.163574,396.009857 933.404907,387.354492 948.665955,378.735077
C958.117737,373.396698 967.561096,368.043396 977.761169,362.270630
C978.580688,367.972168 979.491760,372.861908 979.951111,377.793671
C981.078552,389.897369 981.855286,402.034393 983.036621,414.132294
C984.548767,429.616913 986.405823,445.067780 987.944885,460.549988
C988.806702,469.219269 989.178650,477.937164 990.036194,486.606964
C991.212280,498.497375 992.681763,510.358459 993.943848,522.240784
C994.706360,529.419556 995.313538,536.614746 995.992004,543.802490
C996.993530,554.413513 998.003357,565.023804 998.986450,575.636536
C999.076660,576.610718 998.998474,577.600464 998.998474,579.035278
C974.729675,573.804138 950.873535,568.661987 926.648804,563.294678
z"
/>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB