├── .gitignore ├── .npmrc ├── .streerc ├── .rubocop.yml ├── .prettierrc.cjs ├── .template-lintrc.cjs ├── stylelint.config.mjs ├── eslint.config.mjs ├── Gemfile ├── spec ├── system │ └── core_features_spec.rb ├── integration │ └── overrides_email_spec.rb └── plugin_spec.rb ├── config ├── locales │ ├── client.en.yml │ ├── client.be.yml │ ├── client.bg.yml │ ├── client.ca.yml │ ├── client.cs.yml │ ├── client.da.yml │ ├── client.et.yml │ ├── client.gl.yml │ ├── client.hr.yml │ ├── client.hy.yml │ ├── client.id.yml │ ├── client.ko.yml │ ├── client.lt.yml │ ├── client.lv.yml │ ├── client.pt.yml │ ├── client.ro.yml │ ├── client.sk.yml │ ├── client.sl.yml │ ├── client.sq.yml │ ├── client.sr.yml │ ├── client.sw.yml │ ├── client.te.yml │ ├── client.th.yml │ ├── client.ug.yml │ ├── client.uk.yml │ ├── client.ur.yml │ ├── client.vi.yml │ ├── server.be.yml │ ├── server.bg.yml │ ├── server.cs.yml │ ├── server.da.yml │ ├── server.et.yml │ ├── server.gl.yml │ ├── server.hr.yml │ ├── server.id.yml │ ├── server.lt.yml │ ├── server.lv.yml │ ├── server.ro.yml │ ├── server.sk.yml │ ├── server.sl.yml │ ├── server.sq.yml │ ├── server.sr.yml │ ├── server.te.yml │ ├── server.th.yml │ ├── server.ug.yml │ ├── server.vi.yml │ ├── client.bs_BA.yml │ ├── client.en_GB.yml │ ├── client.nb_NO.yml │ ├── client.pl_PL.yml │ ├── client.zh_TW.yml │ ├── server.en_GB.yml │ ├── server.fa_IR.yml │ ├── server.nb_NO.yml │ ├── server.zh_TW.yml │ ├── client.ar.yml │ ├── client.es.yml │ ├── client.fi.yml │ ├── client.fr.yml │ ├── client.hu.yml │ ├── client.it.yml │ ├── client.ja.yml │ ├── client.nl.yml │ ├── client.ru.yml │ ├── client.sv.yml │ ├── server.el.yml │ ├── client.fa_IR.yml │ ├── client.pt_BR.yml │ ├── client.tr_TR.yml │ ├── client.zh_CN.yml │ ├── client.de.yml │ ├── client.el.yml │ ├── client.he.yml │ ├── server.bs_BA.yml │ ├── server.sw.yml │ ├── server.uk.yml │ ├── server.pt.yml │ ├── server.hu.yml │ ├── server.hy.yml │ ├── server.ko.yml │ ├── server.ur.yml │ ├── server.pl_PL.yml │ ├── server.zh_CN.yml │ ├── server.ja.yml │ ├── server.ca.yml │ ├── server.en.yml │ ├── server.he.yml │ ├── server.sv.yml │ ├── server.ar.yml │ ├── server.tr_TR.yml │ ├── server.it.yml │ ├── server.fi.yml │ ├── server.ru.yml │ ├── server.nl.yml │ ├── server.de.yml │ ├── server.pt_BR.yml │ ├── server.es.yml │ └── server.fr.yml └── settings.yml ├── translator.yml ├── .github └── workflows │ └── discourse-plugin.yml ├── .discourse-compatibility ├── package.json ├── lib ├── validators │ └── oauth2_basic │ │ └── oauth2_fetch_user_details_validator.rb ├── oauth2_faraday_formatter.rb ├── omniauth │ └── strategies │ │ └── oauth2_basic.rb └── oauth2_basic_authenticator.rb ├── db └── migrate │ └── 20190724055909_move_to_managed_authenticator.rb ├── LICENSE ├── plugin.rb ├── Gemfile.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /gems 3 | /auto_generated 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict = true 2 | auto-install-peers = false 3 | -------------------------------------------------------------------------------- /.streerc: -------------------------------------------------------------------------------- 1 | --print-width=100 2 | --plugins=plugin/trailing_comma 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_gem: 2 | rubocop-discourse: stree-compat.yml 3 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@discourse/lint-configs/prettier"); 2 | -------------------------------------------------------------------------------- /.template-lintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = require("@discourse/lint-configs/template-lint"); 2 | -------------------------------------------------------------------------------- /stylelint.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ["@discourse/lint-configs/stylelint"], 3 | }; 4 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import DiscourseRecommended from "@discourse/lint-configs/eslint"; 2 | 3 | export default [...DiscourseRecommended]; 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | group :development do 6 | gem "rubocop-discourse" 7 | gem "syntax_tree" 8 | end 9 | -------------------------------------------------------------------------------- /spec/system/core_features_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe "Core features", type: :system do 4 | before { enable_current_plugin } 5 | 6 | it_behaves_like "having working core features" 7 | end 8 | -------------------------------------------------------------------------------- /config/locales/client.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | js: 3 | login: 4 | oauth2_basic: 5 | name: "OAuth 2" 6 | admin: 7 | site_settings: 8 | categories: 9 | discourse_oauth2_basic: "OAuth2 Login" 10 | -------------------------------------------------------------------------------- /config/locales/client.be.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | be: 8 | -------------------------------------------------------------------------------- /config/locales/client.bg.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bg: 8 | -------------------------------------------------------------------------------- /config/locales/client.ca.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ca: 8 | -------------------------------------------------------------------------------- /config/locales/client.cs.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | cs: 8 | -------------------------------------------------------------------------------- /config/locales/client.da.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | da: 8 | -------------------------------------------------------------------------------- /config/locales/client.et.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | et: 8 | -------------------------------------------------------------------------------- /config/locales/client.gl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | gl: 8 | -------------------------------------------------------------------------------- /config/locales/client.hr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hr: 8 | -------------------------------------------------------------------------------- /config/locales/client.hy.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hy: 8 | -------------------------------------------------------------------------------- /config/locales/client.id.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | id: 8 | -------------------------------------------------------------------------------- /config/locales/client.ko.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ko: 8 | -------------------------------------------------------------------------------- /config/locales/client.lt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lt: 8 | -------------------------------------------------------------------------------- /config/locales/client.lv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lv: 8 | -------------------------------------------------------------------------------- /config/locales/client.pt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt: 8 | -------------------------------------------------------------------------------- /config/locales/client.ro.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ro: 8 | -------------------------------------------------------------------------------- /config/locales/client.sk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sk: 8 | -------------------------------------------------------------------------------- /config/locales/client.sl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sl: 8 | -------------------------------------------------------------------------------- /config/locales/client.sq.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sq: 8 | -------------------------------------------------------------------------------- /config/locales/client.sr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sr: 8 | -------------------------------------------------------------------------------- /config/locales/client.sw.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sw: 8 | -------------------------------------------------------------------------------- /config/locales/client.te.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | te: 8 | -------------------------------------------------------------------------------- /config/locales/client.th.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | th: 8 | -------------------------------------------------------------------------------- /config/locales/client.ug.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ug: 8 | -------------------------------------------------------------------------------- /config/locales/client.uk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | uk: 8 | -------------------------------------------------------------------------------- /config/locales/client.ur.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ur: 8 | -------------------------------------------------------------------------------- /config/locales/client.vi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | vi: 8 | -------------------------------------------------------------------------------- /config/locales/server.be.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | be: 8 | -------------------------------------------------------------------------------- /config/locales/server.bg.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bg: 8 | -------------------------------------------------------------------------------- /config/locales/server.cs.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | cs: 8 | -------------------------------------------------------------------------------- /config/locales/server.da.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | da: 8 | -------------------------------------------------------------------------------- /config/locales/server.et.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | et: 8 | -------------------------------------------------------------------------------- /config/locales/server.gl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | gl: 8 | -------------------------------------------------------------------------------- /config/locales/server.hr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hr: 8 | -------------------------------------------------------------------------------- /config/locales/server.id.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | id: 8 | -------------------------------------------------------------------------------- /config/locales/server.lt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lt: 8 | -------------------------------------------------------------------------------- /config/locales/server.lv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | lv: 8 | -------------------------------------------------------------------------------- /config/locales/server.ro.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ro: 8 | -------------------------------------------------------------------------------- /config/locales/server.sk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sk: 8 | -------------------------------------------------------------------------------- /config/locales/server.sl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sl: 8 | -------------------------------------------------------------------------------- /config/locales/server.sq.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sq: 8 | -------------------------------------------------------------------------------- /config/locales/server.sr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sr: 8 | -------------------------------------------------------------------------------- /config/locales/server.te.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | te: 8 | -------------------------------------------------------------------------------- /config/locales/server.th.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | th: 8 | -------------------------------------------------------------------------------- /config/locales/server.ug.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ug: 8 | -------------------------------------------------------------------------------- /config/locales/server.vi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | vi: 8 | -------------------------------------------------------------------------------- /translator.yml: -------------------------------------------------------------------------------- 1 | # Configuration file for discourse-translator-bot 2 | 3 | files: 4 | - source_path: config/locales/client.en.yml 5 | destination_path: client.yml 6 | - source_path: config/locales/server.en.yml 7 | destination_path: server.yml 8 | -------------------------------------------------------------------------------- /.github/workflows/discourse-plugin.yml: -------------------------------------------------------------------------------- 1 | name: Discourse Plugin 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | ci: 11 | uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1 12 | -------------------------------------------------------------------------------- /config/locales/client.bs_BA.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bs_BA: 8 | -------------------------------------------------------------------------------- /config/locales/client.en_GB.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | en_GB: 8 | -------------------------------------------------------------------------------- /config/locales/client.nb_NO.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nb_NO: 8 | -------------------------------------------------------------------------------- /config/locales/client.pl_PL.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pl_PL: 8 | -------------------------------------------------------------------------------- /config/locales/client.zh_TW.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_TW: 8 | -------------------------------------------------------------------------------- /config/locales/server.en_GB.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | en_GB: 8 | -------------------------------------------------------------------------------- /config/locales/server.fa_IR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fa_IR: 8 | -------------------------------------------------------------------------------- /config/locales/server.nb_NO.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nb_NO: 8 | -------------------------------------------------------------------------------- /config/locales/server.zh_TW.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_TW: 8 | -------------------------------------------------------------------------------- /.discourse-compatibility: -------------------------------------------------------------------------------- 1 | < 3.5.0.beta1-dev: 6de97fb641cec8a868153c58b0268aee0c3c33d5 2 | < 3.4.0.beta1-dev: f8f051f50aeb45c37ad95b5991cc9eeffcbc2a46 3 | < 3.3.0.beta1-dev: 895db120e3e3f58354fd87e425e21c4066e3c07f 4 | 3.1.999: 2ec8f90bb38dc960e90086de0e65759d72567a09 5 | -------------------------------------------------------------------------------- /config/locales/client.ar.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ar: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.es.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | es: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.fi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fi: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.fr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fr: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.hu.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hu: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.it.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | it: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.ja.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ja: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.nl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nl: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.ru.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ru: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.sv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sv: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/server.el.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | el: 8 | site_settings: 9 | oauth2_disable_csrf: "Απενεργοποίηση ελέγχου CSRF" 10 | -------------------------------------------------------------------------------- /config/locales/client.fa_IR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fa_IR: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.pt_BR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt_BR: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.tr_TR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | tr_TR: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /config/locales/client.zh_CN.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_CN: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "@discourse/lint-configs": "2.21.0", 5 | "ember-template-lint": "7.7.0", 6 | "eslint": "9.27.0", 7 | "prettier": "3.5.3", 8 | "stylelint": "16.19.1" 9 | }, 10 | "engines": { 11 | "node": ">= 22", 12 | "npm": "please-use-pnpm", 13 | "yarn": "please-use-pnpm", 14 | "pnpm": "9.x" 15 | }, 16 | "packageManager": "pnpm@9.15.5" 17 | } 18 | -------------------------------------------------------------------------------- /config/locales/client.de.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | de: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | admin: 13 | site_settings: 14 | categories: 15 | discourse_oauth2_basic: "OAuth2 Anmeldung" 16 | -------------------------------------------------------------------------------- /config/locales/client.el.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | el: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | admin: 13 | site_settings: 14 | categories: 15 | discourse_oauth2_basic: "Σύνδεση OAuth2" 16 | -------------------------------------------------------------------------------- /config/locales/client.he.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | he: 8 | js: 9 | login: 10 | oauth2_basic: 11 | name: "OAuth 2" 12 | admin: 13 | site_settings: 14 | categories: 15 | discourse_oauth2_basic: "כניסה עם OAuth2" 16 | -------------------------------------------------------------------------------- /lib/validators/oauth2_basic/oauth2_fetch_user_details_validator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Oauth2FetchUserDetailsValidator 4 | def initialize(opts = {}) 5 | @opts = opts 6 | end 7 | 8 | def valid_value?(val) 9 | return true if val == "t" 10 | SiteSetting.oauth2_callback_user_id_path.length > 0 11 | end 12 | 13 | def error_message 14 | I18n.t("site_settings.errors.oauth2_fetch_user_details") 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /config/locales/server.bs_BA.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | bs_BA: 8 | login: 9 | authenticator_error_fetch_user_details: "Nije moguće dohvatiti vaše korisničke podatke. Imate li aktivan račun?" 10 | site_settings: 11 | oauth2_enabled: "Prilagođeni OAuth2 je omogućen" 12 | oauth2_client_id: "ID klijenta za prilagođeni OAuth2" 13 | oauth2_client_secret: "Tajna klijenta za prilagođeni OAuth2" 14 | oauth2_authorize_url: "URL autorizacije za OAuth2" 15 | -------------------------------------------------------------------------------- /config/locales/server.sw.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sw: 8 | site_settings: 9 | oauth2_enabled: "Custom OAuth2 imeruhusiwa" 10 | oauth2_client_id: "Utambulisho wa Mteja kwa ajili ya OAuth2 binafsi" 11 | oauth2_client_secret: "Mteja wa Siri wa OAuth2 binafsi" 12 | oauth2_token_url_method: "Njia inayotumika kupata anwani ya Token" 13 | oauth2_user_json_url_method: "Njia inayotumika kupata anwani ya JSON ya mtumiaji" 14 | oauth2_email_verified: "Angalia hii kama tovuti ya OAuth2 imethibitisha barua pepe" 15 | -------------------------------------------------------------------------------- /lib/oauth2_faraday_formatter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "faraday/logging/formatter" 4 | 5 | class OAuth2FaradayFormatter < Faraday::Logging::Formatter 6 | def request(env) 7 | warn <<~LOG 8 | OAuth2 Debugging: request #{env.method.upcase} #{env.url} 9 | 10 | Headers: 11 | #{env.request_headers.to_yaml} 12 | 13 | Body: 14 | #{env[:body].to_yaml} 15 | LOG 16 | end 17 | 18 | def response(env) 19 | warn <<~LOG 20 | OAuth2 Debugging: response status #{env.status} 21 | 22 | From #{env.method.upcase} #{env.url} 23 | 24 | Headers: 25 | #{env.request_headers.to_yaml} 26 | 27 | Body: 28 | #{env[:body].to_yaml} 29 | LOG 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /config/locales/server.uk.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | uk: 8 | login: 9 | authenticator_error_fetch_user_details: "Не вдалося отримати дані користувача. У вас є активний обліковий запис?" 10 | site_settings: 11 | oauth2_authorize_options: "Під час авторизації запитувати ці параметри" 12 | oauth2_scope: "Під час авторизації запитувати ці дані" 13 | oauth2_button_title: "Текст кнопки OAuth2" 14 | oauth2_allow_association_change: Дозволити користувачам відключати та знову підключати свої облікові записи від постачальника OAuth2 в Discourse 15 | -------------------------------------------------------------------------------- /db/migrate/20190724055909_move_to_managed_authenticator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MoveToManagedAuthenticator < ActiveRecord::Migration[5.2] 4 | def up 5 | execute <<~SQL 6 | INSERT INTO user_associated_accounts ( 7 | provider_name, 8 | provider_uid, 9 | user_id, 10 | created_at, 11 | updated_at 12 | ) SELECT 13 | 'oauth2_basic', 14 | replace(key, 'oauth2_basic_user_', ''), 15 | (value::json->>'user_id')::integer, 16 | CURRENT_TIMESTAMP, 17 | CURRENT_TIMESTAMP 18 | FROM plugin_store_rows 19 | WHERE plugin_name = 'oauth2_basic' 20 | AND value::json->>'user_id' ~ '^[0-9]+$' 21 | ON CONFLICT (provider_name, user_id) 22 | DO NOTHING 23 | SQL 24 | end 25 | 26 | def down 27 | raise ActiveRecord::IrreversibleMigration 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /config/locales/server.pt.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt: 8 | login: 9 | authenticator_error_fetch_user_details: "Não foi possível recuperar os detalhes do utilizador. Tem uma conta ativa?" 10 | site_settings: 11 | oauth2_enabled: "OAuth2 personalizada está ativada" 12 | oauth2_client_id: "Id. do cliente para OAuth2 personalizada" 13 | oauth2_client_secret: "Segredo de Cliente para OAuth2 personalizada" 14 | oauth2_authorize_url: "URL de autorização para OAuth2" 15 | oauth2_token_url: "URL do código para OAuth2" 16 | oauth2_token_url_method: "Método utilizado para obter o URL do Código" 17 | oauth2_fetch_user_details: "Obter JSON do utilizador para OAuth2" 18 | oauth2_user_json_url_method: "Método utilizado para obter o URL de JSON do utilizador" 19 | -------------------------------------------------------------------------------- /lib/omniauth/strategies/oauth2_basic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class OmniAuth::Strategies::Oauth2Basic < ::OmniAuth::Strategies::OAuth2 4 | option :name, "oauth2_basic" 5 | 6 | uid do 7 | if path = SiteSetting.oauth2_callback_user_id_path.split(".") 8 | recurse(access_token, [*path]) if path.present? 9 | end 10 | end 11 | 12 | info do 13 | if paths = SiteSetting.oauth2_callback_user_info_paths.split("|") 14 | result = Hash.new 15 | paths.each do |p| 16 | segments = p.split(":") 17 | if segments.length == 2 18 | key = segments.first 19 | path = [*segments.last.split(".")] 20 | result[key] = recurse(access_token, path) 21 | end 22 | end 23 | result 24 | end 25 | end 26 | 27 | def callback_url 28 | Discourse.base_url_no_prefix + script_name + callback_path 29 | end 30 | 31 | def recurse(obj, keys) 32 | return nil if !obj 33 | k = keys.shift 34 | result = obj.respond_to?(k) ? obj.send(k) : obj[k] 35 | keys.empty? ? result : recurse(result, keys) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Civilized Discourse Construction Kit, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/locales/server.hu.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hu: 8 | login: 9 | authenticator_error_fetch_user_details: "Nem sikerült lekérni a felhasználói adatokat. Van aktív fiókja?" 10 | site_settings: 11 | oauth2_enabled: "Az egyéni OAuth2 engedélyezett" 12 | oauth2_client_id: "Kliensazonosító az egyéni OAuth2-höz" 13 | oauth2_client_secret: "Kliens titka az egyéni OAuth2-höz" 14 | oauth2_authorize_url: "Az OAuth2 engedélyezési URL-je" 15 | oauth2_authorize_signup_url: '(nem kötelező) A „Regisztráció” gomb használatakor használt alternatív engedélyezési URL' 16 | oauth2_token_url: "Az OAuth2 token URL-je" 17 | oauth2_token_url_method: "A Token URL lekéréséhez használt módszer" 18 | oauth2_callback_user_id_path: "Útvonal a token válaszában a felhasználói azonosítóhoz. Például params.info.uuid" 19 | oauth2_callback_user_info_paths: "Útvonalak a token válaszában más felhasználói tulajdonságokhoz. A támogatott tulajdonságok: name, username, email, email_verified és avatar. A formátuma tulajdonság:útvonal, például: name:params.info.name" 20 | oauth2_fetch_user_details: "Felhasználói JSON lekérése az OAuth2-höz" 21 | -------------------------------------------------------------------------------- /config/locales/server.hy.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | hy: 8 | site_settings: 9 | oauth2_enabled: "Մասնավոր OAuth2 -ը միացված է" 10 | oauth2_client_id: "Հաճախորդի ID մասնավոր OAuth2 -ի համար" 11 | oauth2_client_secret: "Հաճախորդի Գաղտնի Արժեք մասնավոր OAuth2 -ի համար" 12 | oauth2_authorize_url: "Նույնականացման URL OAuth2 -ի համար" 13 | oauth2_token_url: "Տոկենի URL OAuth2 -ի համար" 14 | oauth2_token_url_method: "Տոկենի URL -ի բեռնման համար օգտագործվող մեթոդ" 15 | oauth2_user_json_url: "OAuth2 -ի համար օգտատիրոջ JSON -ի բեռնման URL (նկատի ունեցեք, որ մենք փոխարինել ենք :id -ն OAuth կանչի կողմից վերադարձված id-ով և :token -ը՝ տոկենի id -ով)" 16 | oauth2_user_json_url_method: "Օգտատիրոջ JSON URL -ի բեռնման համար օգտագործվող մեթոդ" 17 | oauth2_json_user_id_path: "OAuth2 User JSON -ում ուղի դեպի օգտատիրոջ id. օրինակ՝ user.id" 18 | oauth2_json_username_path: "OAuth2 User JSON t-ում ուղի դեպի օգտանուն, օրինակ՝ user.username" 19 | oauth2_email_verified: "Ստուգել սա, եթե OAuth2 կայքը հաստատել է էլ. հասցեն" 20 | oauth2_debug_auth: "Ներառել կարգաբերման հարուստ տեղեկատվություն Ձեր գրառումներում" 21 | oauth2_authorize_options: "Նույնականացման ժամանակ պահանջել այս տարբերակները" 22 | oauth2_scope: "Նույնականացման ժամանակ պահանջել այս սահմանը" 23 | oauth2_button_title: "OAuth2 կոճակի տեքստ" 24 | -------------------------------------------------------------------------------- /config/settings.yml: -------------------------------------------------------------------------------- 1 | login: 2 | oauth2_enabled: 3 | default: false 4 | client: true 5 | oauth2_client_id: "" 6 | oauth2_client_secret: 7 | default: "" 8 | secret: true 9 | oauth2_authorize_url: "" 10 | oauth2_authorize_signup_url: "" 11 | oauth2_token_url: "" 12 | oauth2_token_url_method: 13 | default: "POST" 14 | type: enum 15 | choices: 16 | - GET 17 | - POST 18 | - PUT 19 | oauth2_callback_user_id_path: "" 20 | oauth2_callback_user_info_paths: 21 | type: list 22 | default: "id" 23 | oauth2_fetch_user_details: 24 | default: true 25 | validator: "Oauth2FetchUserDetailsValidator" 26 | oauth2_user_json_url: "" 27 | oauth2_user_json_url_method: 28 | default: "GET" 29 | type: enum 30 | choices: 31 | - GET 32 | - POST 33 | oauth2_json_user_id_path: "" 34 | oauth2_json_username_path: "" 35 | oauth2_json_name_path: "" 36 | oauth2_json_email_path: "" 37 | oauth2_json_email_verified_path: "" 38 | oauth2_json_avatar_path: "" 39 | oauth2_email_verified: false 40 | oauth2_overrides_email: false 41 | oauth2_send_auth_header: true 42 | oauth2_send_auth_body: true 43 | oauth2_debug_auth: false 44 | oauth2_authorize_options: 45 | default: "scope" 46 | type: list 47 | oauth2_scope: "" 48 | oauth2_button_title: 49 | default: "with OAuth2" 50 | client: true 51 | oauth2_allow_association_change: 52 | default: false 53 | oauth2_disable_csrf: 54 | default: false 55 | hidden: true 56 | -------------------------------------------------------------------------------- /plugin.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # name: discourse-oauth2-basic 4 | # about: Allows users to login to your forum using a basic OAuth2 provider. 5 | # meta_topic_id: 33879 6 | # version: 0.3 7 | # authors: Robin Ward 8 | # url: https://github.com/discourse/discourse-oauth2-basic 9 | 10 | enabled_site_setting :oauth2_enabled 11 | 12 | require_relative "lib/omniauth/strategies/oauth2_basic" 13 | require_relative "lib/oauth2_faraday_formatter" 14 | require_relative "lib/oauth2_basic_authenticator" 15 | 16 | # You should use this register if you want to add custom paths to traverse the user details JSON. 17 | # We'll store the value in the user associated account's extra attribute hash using the full path as the key. 18 | DiscoursePluginRegistry.define_filtered_register :oauth2_basic_additional_json_paths 19 | 20 | # After authentication, we'll use this to confirm that the registered json paths are fulfilled, or display an error. 21 | # This requires SiteSetting.oauth2_fetch_user_details? to be true, and can be used with 22 | # DiscoursePluginRegistry.oauth2_basic_additional_json_paths. 23 | # 24 | # Example usage: 25 | # DiscoursePluginRegistry.register_oauth2_basic_required_json_path({ 26 | # path: "extra:data.is_allowed_user", 27 | # required_value: true, 28 | # error_message: I18n.t("auth.user_not_allowed") 29 | # }, self) 30 | DiscoursePluginRegistry.define_filtered_register :oauth2_basic_required_json_paths 31 | 32 | auth_provider title_setting: "oauth2_button_title", authenticator: OAuth2BasicAuthenticator.new 33 | 34 | require_relative "lib/validators/oauth2_basic/oauth2_fetch_user_details_validator" 35 | -------------------------------------------------------------------------------- /spec/integration/overrides_email_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe "OAuth2 Overrides Email", type: :request do 6 | fab!(:initial_email) { "initial@example.com" } 7 | fab!(:new_email) { "new@example.com" } 8 | fab!(:user) { Fabricate(:user, email: initial_email) } 9 | fab!(:uac) do 10 | UserAssociatedAccount.create!(user: user, provider_name: "oauth2_basic", provider_uid: "12345") 11 | end 12 | 13 | before do 14 | SiteSetting.oauth2_enabled = true 15 | SiteSetting.oauth2_callback_user_id_path = "uid" 16 | SiteSetting.oauth2_fetch_user_details = false 17 | SiteSetting.oauth2_email_verified = true 18 | 19 | OmniAuth.config.test_mode = true 20 | OmniAuth.config.mock_auth[:oauth2_basic] = OmniAuth::AuthHash.new( 21 | provider: "oauth2_basic", 22 | uid: "12345", 23 | info: OmniAuth::AuthHash::InfoHash.new(email: new_email), 24 | extra: { 25 | raw_info: OmniAuth::AuthHash.new(email_verified: true), 26 | }, 27 | credentials: OmniAuth::AuthHash.new, 28 | ) 29 | end 30 | 31 | it "doesn't update email by default" do 32 | expect(user.reload.email).to eq(initial_email) 33 | 34 | get "/auth/oauth2_basic/callback" 35 | expect(response.status).to eq(302) 36 | expect(session[:current_user_id]).to eq(user.id) 37 | 38 | expect(user.reload.email).to eq(initial_email) 39 | end 40 | 41 | it "updates user email if enabled" do 42 | SiteSetting.oauth2_overrides_email = true 43 | 44 | get "/auth/oauth2_basic/callback" 45 | expect(response.status).to eq(302) 46 | expect(session[:current_user_id]).to eq(user.id) 47 | 48 | expect(user.reload.email).to eq(new_email) 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /config/locales/server.ko.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ko: 8 | login: 9 | authenticator_error_fetch_user_details: "사용자 세부 정보를 검색 할 수 없습니다. 활성 계정이 있습니까?" 10 | site_settings: 11 | oauth2_enabled: "맞춤 OAuth2가 사용 설정되었습니다." 12 | oauth2_client_id: "사용자 정의 OAuth2의 클라이언트 ID" 13 | oauth2_client_secret: "커스텀 OAuth2를위한 클라이언트 시크릿" 14 | oauth2_authorize_url: "OAuth2의 인증 URL" 15 | oauth2_token_url: "OAuth2의 토큰 URL" 16 | oauth2_token_url_method: "토큰 URL을 가져 오는 데 사용되는 방법" 17 | oauth2_callback_user_id_path: "사용자 ID에 대한 토큰 응답의 경로입니다. 예 : params.info.uuid" 18 | oauth2_callback_user_info_paths: "다른 사용자 속성에 대한 토큰 응답의 경로 지원되는 속성은 이름, 사용자 이름, 이메일, email_verified 및 아바타입니다. 형식은 property : path입니다 (예 : name : params.info.name)." 19 | oauth2_fetch_user_details: "OAuth2 용 사용자 JSON 가져 오기" 20 | oauth2_user_json_url: "OAuth2 용 사용자 JSON을 가져 오는 URL (: 우리는 : Auth를 OAuth 호출에서 반환 한 ID로 대체하고 : token을 토큰 ID로 대체합니다)" 21 | oauth2_user_json_url_method: "사용자 JSON URL을 가져 오는 데 사용되는 메소드" 22 | oauth2_json_user_id_path: "OAuth2 사용자 JSON에서 사용자 ID의 경로입니다. 예 : user.id" 23 | oauth2_json_username_path: "OAuth2 사용자 JSON에서 사용자 이름으로의 경로입니다. 예 : user.username" 24 | oauth2_json_name_path: "OAuth2 사용자 JSON에서 사용자의 전체 경로입니다. 예 : user.name.full" 25 | oauth2_json_email_path: "OAuth2 사용자 JSON에서 사용자의 이메일 경로입니다. 예 : user.email" 26 | oauth2_json_email_verified_path: "OAuth2 사용자 JSON의 경로를 사용자의 이메일 확인 상태로 지정하십시오. 예 : user.email.verified. 이 설정을 적용하려면 oauth2_email_verified를 비활성화해야합니다" 27 | oauth2_json_avatar_path: "Oauth2 사용자 JSON에서 사용자 아바타의 경로입니다. 예 : user.avatar_url" 28 | oauth2_email_verified: "OAuth2 사이트에서 이메일을 확인한 경우이를 확인하십시오." 29 | oauth2_debug_auth: "로그에 풍부한 디버깅 정보 포함" 30 | oauth2_authorize_options: "요청을 승인 할 때 이러한 옵션" 31 | oauth2_scope: "이 범위 요청을 승인 할 때" 32 | oauth2_button_title: "OAuth2 버튼의 텍스트" 33 | oauth2_allow_association_change: 사용자가 OAuth2 공급자와의 담화 계정 연결을 끊었다가 다시 연결하도록 허용 34 | errors: 35 | oauth2_fetch_user_details: "oauth2_fetch_user_details를 비활성화하려면 oauth2_callback_user_id_path가 있어야합니다." 36 | -------------------------------------------------------------------------------- /config/locales/server.ur.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ur: 8 | login: 9 | authenticator_error_fetch_user_details: "آپ کی صارف تفصیلات کو حاصل نہیں کیا جا سکا۔ کیا آپ کے پاس ایک فعال اکاؤنٹ ہے؟" 10 | site_settings: 11 | oauth2_enabled: "اپنی مرضی کا OAuth2 فعال ہے" 12 | oauth2_client_id: "اپنی مرضی کے OAuth2 کیلئے کلائنٹ ائی ڈی" 13 | oauth2_client_secret: "اپنی مرضی کے OAuth2 کیلئے کلائنٹ سیکرٹ" 14 | oauth2_authorize_url: "OAuth2 کے لئے اَوتھرٰیزیشن URL" 15 | oauth2_token_url: "OAuth2 کیلئے ٹوکن URL" 16 | oauth2_token_url_method: "ٹوکن URL حاصل کرنے کا طریقہ" 17 | oauth2_callback_user_id_path: "ٹَوکن جواب میں صارف آئی ڈیکا پاتھ۔ مثال: params.info.uuid" 18 | oauth2_callback_user_info_paths: " ٹَوکن جواب میں دیگر صارف خصوصیات کے پاتھ۔ معاون خصوصیات، نام، صارف نام، ایمیل، ایمیل_توثیق_شدہ اور اوتار ہیں۔ فارمیٹ ہے property:path، مثال: name:params.info.name" 19 | oauth2_fetch_user_details: "OAuth2 کیلئے صارف JSON حاصل کریں" 20 | oauth2_user_json_url: "OAuth2 کیلئے صارف کا JSON حاصل کرنے کا URL (نوٹ کریں کہ ہم :id کو OAuth کال سے حاصل ہوئی id اور :token کو ٹوکن id سے تبدیل کر دیتے ہیں)" 21 | oauth2_user_json_url_method: "صارف JSON URL حاصل کرنے کا طریقہ" 22 | oauth2_json_user_id_path: "OAuth2 صارف JSON میں صارف آئی ڈی کا پاتھ۔ مثال: user.id" 23 | oauth2_json_username_path: "OAuth2 صارف JSON میں صارف نام کا پاتھ۔ مثال: user.username" 24 | oauth2_email_verified: "اِس کو چیک لگائیں اگر OAuth2 سائٹ نے ای مَیل کی توثیق کی ہوئی ہے" 25 | oauth2_debug_auth: "اپنے لاگز میں رِچ ڈیبگنگ معلومات شامل کریں" 26 | oauth2_authorize_options: "جب اَوتھرٰیز کیا جا رہا ہو تو اِن اختیارات کی درخواست کریں" 27 | oauth2_scope: "اَوتھرائز کرتے وقت اِس سکَوپ کی درخواست کریں" 28 | oauth2_button_title: "OAuth2 بٹن کیلئے متن" 29 | oauth2_allow_association_change: صارفین کو OAuth2 فراہم کنندہ سے اپنے ڈِسکَورس اکاؤنٹس کو منقطع اور دوبارہ کنیکٹ کرنے کی اجازت دیں 30 | errors: 31 | oauth2_fetch_user_details: "oauth2_fetch_user_details غیر فعال کرنے کیلئے oauth2_callback_user_id_path کا موجود ہونا لاذمی ہے" 32 | -------------------------------------------------------------------------------- /config/locales/server.pl_PL.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pl_PL: 8 | login: 9 | authenticator_error_fetch_user_details: "Nie mogliśmy odnaleźć informacji o Twoim użytkowniku. Czy Twoje konto jest aktywne?" 10 | site_settings: 11 | oauth2_enabled: "Niestandardowy OAuth2 jest włączony" 12 | oauth2_client_id: "Client ID dla własnego OAuth2" 13 | oauth2_client_secret: "Client Secret dla własnego OAuth2" 14 | oauth2_authorize_url: "Adres URL autoryzacji dla OAuth2" 15 | oauth2_token_url: "Token URL dla OAuth2" 16 | oauth2_token_url_method: "Metoda używana do pozyskania URL tokenu" 17 | oauth2_callback_user_id_path: "Ścieżka w tokenie-odpowiedzi do ID użytkownika, np. params.info.uuid" 18 | oauth2_callback_user_info_paths: "Ścieżka w tokenie-odpowiedzi do innych właściwości użytkownika. Wspierane właściwości to nazwa, nazwa użytkownika, email, informacja czy email został zweryfikowany, awatar. Format to właściwość:ścieżka, np. name:params.info.name" 19 | oauth2_fetch_user_details: "Pobierz JSON użytkownika dla OAuth2" 20 | oauth2_user_json_url: "URL do pozyskania użytkownika JSON dla OAuth2 (pamiętaj, ze zamieniliśmy :id ID zwracanym przez OAuth i :token ID tokenu)" 21 | oauth2_user_json_url_method: "Metoda używana do pozyskania JSON URL użytkownika" 22 | oauth2_json_user_id_path: "Ścieżka w JSON‐ie użytkownika OAuth2 do ID użytkownika, np.: user.id" 23 | oauth2_json_username_path: "Ścieżka w JSON‐ie użytkownika OAuth2 do nazwy użytkownika, np.: user.username" 24 | oauth2_email_verified: "Sprawdź to, czy witryna OAuth2 zweryfikowała adres e-mail" 25 | oauth2_debug_auth: "Umieść bogate informacje debugowania w swoich logach" 26 | oauth2_authorize_options: "Przy autoryzacji wymagaj tych opcji" 27 | oauth2_scope: "Przy autoryzacji wymagaj tego zakresu" 28 | oauth2_button_title: "Tekst dla przycisku OAuth2" 29 | oauth2_allow_association_change: Zezwól użytkownikom na odłączanie i ponowne łączenie ich kont Discourse od providera OAuth2 30 | errors: 31 | oauth2_fetch_user_details: "oauth2_callback_user_id_path musi być obecne, by dezaktywować oauth2_fetch_user_details" 32 | -------------------------------------------------------------------------------- /config/locales/server.zh_CN.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | zh_CN: 8 | login: 9 | authenticator_error_fetch_user_details: "无法检索您的用户详细信息。您有活跃帐户吗?" 10 | site_settings: 11 | oauth2_enabled: "自定义 OAuth2 已启用" 12 | oauth2_client_id: "自定义 OAuth2 的客户端 ID" 13 | oauth2_client_secret: "自定义 OAuth2 的客户端密钥" 14 | oauth2_authorize_url: "OAuth2 的授权 URL" 15 | oauth2_authorize_signup_url: '(可选)使用“注册”按钮时使用的替代授权 URL' 16 | oauth2_token_url: "OAuth2 的令牌 URL" 17 | oauth2_token_url_method: "用于获取令牌 URL 的方法" 18 | oauth2_callback_user_id_path: "令牌响应中用户 ID 的路径。例如:params.info.uuid" 19 | oauth2_callback_user_info_paths: "令牌响应中其他用户属性的路径。支持的属性包括 name、username、email、email_verified 和 avatar。格式为 property:path,例如:name:params.info.name" 20 | oauth2_fetch_user_details: "获取 OAuth2 的用户 JSON" 21 | oauth2_user_json_url: "用于获取 OAuth2 的用户 JSON 的 URL(请注意,我们将 :id 替换为 OAuth 调用返回的 ID,将 :token 替换为令牌 ID)" 22 | oauth2_user_json_url_method: "用于获取用户 JSON URL 的方法" 23 | oauth2_json_user_id_path: "OAuth2 用户 JSON 中用户 ID 的路径。例如:user.id" 24 | oauth2_json_username_path: "OAuth2 用户 JSON 中用户名的路径。例如:user.username" 25 | oauth2_json_name_path: "OAuth2 用户 JSON 中用户全名的路径。例如:user.name.full" 26 | oauth2_json_email_path: "OAuth2 用户 JSON 中用户电子邮件的路径。例如:user.email" 27 | oauth2_json_email_verified_path: "OAuth2 用户 JSON 中用户电子邮件验证状态的路径。例如:user.email.verified。要使该设置生效,必须禁用 oauth2_email_verified" 28 | oauth2_json_avatar_path: "OAuth2 用户 JSON 中用户头像的路径。例如:user.avatar_url" 29 | oauth2_email_verified: "如果 OAuth2 站点已验证电子邮件,请选中此项" 30 | oauth2_overrides_email: "在每次登录时使用远程电子邮件替换 Discourse 电子邮件。工作方式与 `auth_overrides_email` 设置相同,但特定于 OAuth2 登录。" 31 | oauth2_send_auth_header: "在 HTTP 授权标头中发送客户端凭据" 32 | oauth2_send_auth_body: "在请求正文中发送客户端凭据" 33 | oauth2_debug_auth: "在日志中包含丰富的调试信息" 34 | oauth2_authorize_options: "授权时请求这些选项" 35 | oauth2_scope: "授权请求此范围时" 36 | oauth2_button_title: "OAuth2 按钮的文本" 37 | oauth2_allow_association_change: 允许用户从 OAuth2 提供商断开并重新连接他们的 Discourse 帐户 38 | oauth2_disable_csrf: "禁用 CSRF 检查" 39 | errors: 40 | oauth2_fetch_user_details: "必须存在 oauth2_callback_user_id_path 才能禁用 oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.ja.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ja: 8 | login: 9 | authenticator_error_fetch_user_details: "ユーザー情報を取得できませんでした。アクティブなアカウントをお持ちですか?" 10 | site_settings: 11 | oauth2_enabled: "カスタム OAuth2 は有効です" 12 | oauth2_client_id: "カスタム OAuth2 のクライアントID" 13 | oauth2_client_secret: "カスタム OAuth2 のクライアントシークレット" 14 | oauth2_authorize_url: "OAuth2 の認証 URL" 15 | oauth2_authorize_signup_url: '(オプション)「登録」ボタンが使用される場合に使用される代替認証 URL' 16 | oauth2_token_url: "OAuth2 のトークン URL" 17 | oauth2_token_url_method: "トークン URL を取得するために使用されるメソッド" 18 | oauth2_callback_user_id_path: "トークン応答内のユーザー ID へのパス。例: params.info.uuid" 19 | oauth2_callback_user_info_paths: "トークン応答内の他のユーザープロパティへのパス。サポートされているプロパティは、name、username、email、email_verified、および avatar です。フォーマットは property:path です。例: name:params.info.name" 20 | oauth2_fetch_user_details: "OAuth2 のユーザー JSON を取得する" 21 | oauth2_user_json_url: "OAuth2 のユーザー JSON を取得するための URL(:id を OAuth の呼び出しが返す id に、:token を token id に置き換えることに注意してください)" 22 | oauth2_user_json_url_method: "ユーザー JSON URL を取得するために使用されるメソッド" 23 | oauth2_json_user_id_path: "OAuth2 ユーザー JSON 内のユーザー ID への パス。例: user.id" 24 | oauth2_json_username_path: "OAuth2 ユーザー JSON 内のユーザー名へのパス。例: user.username" 25 | oauth2_json_name_path: "OAuth2 ユーザー JSON 内のユーザーの氏名(フルネーム)へのパス。例: user.name.full" 26 | oauth2_json_email_path: "OAuth2 ユーザー JSON 内のユーザーのメールアドレスへのパス。例: user.email" 27 | oauth2_json_email_verified_path: "OAuth2 ユーザー JSON 内のユーザーのメールアドレス確認ステータスへのパス。例: user.email.verified。この設定を有効にするには、oauth2_email_verified を無効にする必要があります" 28 | oauth2_json_avatar_path: "OAuth2 ユーザー JSON 内のユーザーのアバターへのパス。例: user.avatar_url" 29 | oauth2_email_verified: "OAuth2 サイトがメールアドレスを確認した場合はこれをオンにする" 30 | oauth2_overrides_email: "ログインのたびに、Discourse メールアドレスをリモートメールアドレスでオーバーライドする。 `auth_overrides_email` 設定と同様に機能しますが、OAuth2 ログインに特化しています。" 31 | oauth2_send_auth_header: "クライアントの資格情報を HTTP 認証ヘッダーで送信する" 32 | oauth2_send_auth_body: "クライアントの資格情報をリクエスト本文で送信する" 33 | oauth2_debug_auth: "ログに詳細なデバッグ情報を含める" 34 | oauth2_authorize_options: "承認中にこれらのオプションをリクエストする" 35 | oauth2_scope: "承認中にこの範囲をリクエストする" 36 | oauth2_button_title: "OAuth2 ボタンのテキスト" 37 | oauth2_allow_association_change: ユーザーが OAuth2 プロバイダーから Discourse アカウントを切断または再接続することを許可する 38 | oauth2_disable_csrf: "CSRF チェックを無効にする" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_fetch_user_details を無効にするには、oauth2_callback_user_id_path が存在する必要があります" 41 | -------------------------------------------------------------------------------- /config/locales/server.ca.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ca: 8 | login: 9 | authenticator_error_fetch_user_details: "No s'han pogut recuperar les dades d'usuari. Teniu un compte actiu?" 10 | site_settings: 11 | oauth2_enabled: "OAuth2 personalitzat està habilitat" 12 | oauth2_client_id: "ID de client per a OAuth2 personalitzat" 13 | oauth2_client_secret: "Secret del client per a OAuth2 personalitzat" 14 | oauth2_authorize_url: "URL d'autorització per a OAuth2" 15 | oauth2_token_url: "URL del testimoni per a OAuth2" 16 | oauth2_token_url_method: "Mètode que s'utilitza per a obtenir l'URL del testimoni" 17 | oauth2_callback_user_id_path: "Camí en la resposta del testimoni a l'identificador de l'usuari, p. ex. params.info.uuid" 18 | oauth2_callback_user_info_paths: "Camins en la resposta de testimoni a altres propietats de l'usuari. Les propietats compatibles són: name, username, email, email_verified i avatar. El format és propietat:camí, per exemple name:params.info.name" 19 | oauth2_fetch_user_details: "Obté el JSON d'usuari per a OAuth2" 20 | oauth2_user_json_url: "URL per a obtenir el JSON d'usuari per a OAuth2 (tingueu en compte que reemplacem :id amb l'identificador retornat per la crida OAuth i :token amb l'identificador de testimoni)" 21 | oauth2_user_json_url_method: "Mètode utilitzat per a obtenir l'URL de l'usuari JSON" 22 | oauth2_json_user_id_path: "Camí en el JSON d'usuari OAuth2 a l'identificador d'usuari, p. ex.: user.id" 23 | oauth2_json_username_path: "Camí en el JSON d'usuari OAuth2 al nom d'usuari, p. ex.: user.username" 24 | oauth2_json_name_path: "Ruta d'accés en el JSON d'usuari OAuth2 al nom complet d'usuari. Per exemple: user.name.full" 25 | oauth2_json_email_path: "Ruta d'accés en el JSON d'usuari OAuth2 al correu electrònic d'usuari. Per exemple: user.email" 26 | oauth2_email_verified: "Comprova-ho si el lloc web OAuth2 ha verificat el correu electrònic" 27 | oauth2_send_auth_header: "Envia les credencials de client en una capçalera d’autorització HTTP" 28 | oauth2_debug_auth: "Inclou informació de depuració enriquida en els registres" 29 | oauth2_authorize_options: "En autoritzar sol·licita aquestes opcions" 30 | oauth2_scope: "En autoritzar sol·licita aquest abast" 31 | oauth2_button_title: "Text del botó OAuth2" 32 | oauth2_allow_association_change: Permet als usuaris desconnectar i reconnectar els comptes de Discourse des del proveïdor OAuth2 33 | errors: 34 | oauth2_fetch_user_details: "oauth2_callback_user_id_p_path ha de ser present per a inhabilitar oauth2_fetch_user_details" 35 | -------------------------------------------------------------------------------- /config/locales/server.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | login: 3 | authenticator_error_fetch_user_details: "Could not retrieve your user details. Do you have an active account?" 4 | 5 | site_settings: 6 | oauth2_enabled: "Custom OAuth2 is enabled" 7 | oauth2_client_id: "Client ID for custom OAuth2" 8 | oauth2_client_secret: "Client Secret for custom OAuth2" 9 | oauth2_authorize_url: "Authorization URL for OAuth2" 10 | oauth2_authorize_signup_url: '(optional) Alternative authorization URL used when the "Sign Up" button is used' 11 | oauth2_token_url: "Token URL for OAuth2" 12 | oauth2_token_url_method: "Method used to fetch the Token URL" 13 | oauth2_callback_user_id_path: "Path in the token response to the user id. eg: params.info.uuid" 14 | oauth2_callback_user_info_paths: "Paths in the token response to other user properties. Supported properties are name, username, email, email_verified and avatar. Format is property:path, eg: name:params.info.name" 15 | oauth2_fetch_user_details: "Fetch user JSON for OAuth2" 16 | oauth2_user_json_url: "URL to fetch user JSON for OAuth2 (note we replace :id with the id returned by OAuth call and :token with the token id)" 17 | oauth2_user_json_url_method: "Method used to fetch the user JSON URL" 18 | oauth2_json_user_id_path: "Path in the OAuth2 User JSON to the user id. eg: user.id" 19 | oauth2_json_username_path: "Path in the OAuth2 User JSON to the username. eg: user.username" 20 | oauth2_json_name_path: "Path in the OAuth2 User JSON to the user's full. eg: user.name.full" 21 | oauth2_json_email_path: "Path in the OAuth2 User JSON to the user's email. eg: user.email" 22 | oauth2_json_email_verified_path: "Path in the OAuth2 User JSON to the user's email verification state. eg: user.email.verified. oauth2_email_verified must be disabled for this setting to have any effect" 23 | oauth2_json_avatar_path: "Path in the Oauth2 User JSON to the user's avatar. eg: user.avatar_url" 24 | oauth2_email_verified: "Check this if the OAuth2 site has verified the email" 25 | oauth2_overrides_email: "Override the Discourse email with the remote email on every login. Works the same as the `auth_overrides_email` setting, but is specific to OAuth2 logins." 26 | oauth2_send_auth_header: "Send client credentials in an HTTP Authorization header" 27 | oauth2_send_auth_body: "Send client credentials in the request body" 28 | oauth2_debug_auth: "Include rich debugging information in your logs" 29 | oauth2_authorize_options: "When authorizing request these options" 30 | oauth2_scope: "When authorizing request this scope" 31 | oauth2_button_title: "The text for the OAuth2 button" 32 | oauth2_allow_association_change: Allow users to disconnect and reconnect their Discourse accounts from the OAuth2 provider 33 | oauth2_disable_csrf: "Disable CSRF check" 34 | 35 | errors: 36 | oauth2_fetch_user_details: "oauth2_callback_user_id_path must be present to disable oauth2_fetch_user_details" 37 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (8.0.2) 5 | base64 6 | benchmark (>= 0.3) 7 | bigdecimal 8 | concurrent-ruby (~> 1.0, >= 1.3.1) 9 | connection_pool (>= 2.2.5) 10 | drb 11 | i18n (>= 1.6, < 2) 12 | logger (>= 1.4.2) 13 | minitest (>= 5.1) 14 | securerandom (>= 0.3) 15 | tzinfo (~> 2.0, >= 2.0.5) 16 | uri (>= 0.13.1) 17 | ast (2.4.3) 18 | base64 (0.2.0) 19 | benchmark (0.4.0) 20 | bigdecimal (3.1.9) 21 | concurrent-ruby (1.3.5) 22 | connection_pool (2.5.3) 23 | drb (2.2.3) 24 | i18n (1.14.7) 25 | concurrent-ruby (~> 1.0) 26 | json (2.12.2) 27 | language_server-protocol (3.17.0.5) 28 | lint_roller (1.1.0) 29 | logger (1.7.0) 30 | minitest (5.25.5) 31 | parallel (1.27.0) 32 | parser (3.3.8.0) 33 | ast (~> 2.4.1) 34 | racc 35 | prettier_print (1.2.1) 36 | prism (1.4.0) 37 | racc (1.8.1) 38 | rack (3.1.16) 39 | rainbow (3.1.1) 40 | regexp_parser (2.10.0) 41 | rubocop (1.75.8) 42 | json (~> 2.3) 43 | language_server-protocol (~> 3.17.0.2) 44 | lint_roller (~> 1.1.0) 45 | parallel (~> 1.10) 46 | parser (>= 3.3.0.2) 47 | rainbow (>= 2.2.2, < 4.0) 48 | regexp_parser (>= 2.9.3, < 3.0) 49 | rubocop-ast (>= 1.44.0, < 2.0) 50 | ruby-progressbar (~> 1.7) 51 | unicode-display_width (>= 2.4.0, < 4.0) 52 | rubocop-ast (1.44.1) 53 | parser (>= 3.3.7.2) 54 | prism (~> 1.4) 55 | rubocop-capybara (2.22.1) 56 | lint_roller (~> 1.1) 57 | rubocop (~> 1.72, >= 1.72.1) 58 | rubocop-discourse (3.12.1) 59 | activesupport (>= 6.1) 60 | lint_roller (>= 1.1.0) 61 | rubocop (>= 1.73.2) 62 | rubocop-capybara (>= 2.22.0) 63 | rubocop-factory_bot (>= 2.27.0) 64 | rubocop-rails (>= 2.30.3) 65 | rubocop-rspec (>= 3.0.1) 66 | rubocop-rspec_rails (>= 2.31.0) 67 | rubocop-factory_bot (2.27.1) 68 | lint_roller (~> 1.1) 69 | rubocop (~> 1.72, >= 1.72.1) 70 | rubocop-rails (2.32.0) 71 | activesupport (>= 4.2.0) 72 | lint_roller (~> 1.1) 73 | rack (>= 1.1) 74 | rubocop (>= 1.75.0, < 2.0) 75 | rubocop-ast (>= 1.44.0, < 2.0) 76 | rubocop-rspec (3.6.0) 77 | lint_roller (~> 1.1) 78 | rubocop (~> 1.72, >= 1.72.1) 79 | rubocop-rspec_rails (2.31.0) 80 | lint_roller (~> 1.1) 81 | rubocop (~> 1.72, >= 1.72.1) 82 | rubocop-rspec (~> 3.5) 83 | ruby-progressbar (1.13.0) 84 | securerandom (0.4.1) 85 | syntax_tree (6.2.0) 86 | prettier_print (>= 1.2.0) 87 | tzinfo (2.0.6) 88 | concurrent-ruby (~> 1.0) 89 | unicode-display_width (3.1.4) 90 | unicode-emoji (~> 4.0, >= 4.0.4) 91 | unicode-emoji (4.0.4) 92 | uri (1.0.3) 93 | 94 | PLATFORMS 95 | ruby 96 | 97 | DEPENDENCIES 98 | rubocop-discourse 99 | syntax_tree 100 | 101 | BUNDLED WITH 102 | 2.6.9 103 | -------------------------------------------------------------------------------- /config/locales/server.he.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | he: 8 | login: 9 | authenticator_error_fetch_user_details: "לא ניתן לקבל את פרטי המשתמש שלך. יש לך חשבון פעיל?" 10 | site_settings: 11 | oauth2_enabled: "מופעל OAuth2 בהתאמה אישית" 12 | oauth2_client_id: "מזהה לקוח ל־OAuth2 בהתאמה אישית" 13 | oauth2_client_secret: "סוד לקוח ל־OAuth2 בהתאמה אישית" 14 | oauth2_authorize_url: "כתובת אימות ל־OAuth2" 15 | oauth2_authorize_signup_url: '(רשות) כתובת חלופית להרשאה בה ייעשה שימוש עם לחיצה על הכפתור „הרשמה”' 16 | oauth2_token_url: "כתובת אסימון ל־OAuth2" 17 | oauth2_token_url_method: "שיטה שמשמשת לקבלת כתובת האסימון" 18 | oauth2_callback_user_id_path: "נתיב בתגובת האסימון למזהה המשתמש, למשל: params.info.uuid" 19 | oauth2_callback_user_info_paths: "נתיבים בתגובת האסימון למאפיינים אחרים של משתמשים. המאפיינים הנתמכים הם name,‏ username,‏ email,‏ email_verified ו־avatar (שם, שם משתמש, כתובת דוא״ל, האם הדוא״ל מאומת ותמונה ייצוגית בהתאמה). התצורה היא מאפיין:נתיב, למשל: name:params.info.name" 20 | oauth2_fetch_user_details: "אחזור JSON משתמש עבור OAuth2" 21 | oauth2_user_json_url: "כתובת לקבל ה־JSON של המשתמש לטובת OAuth2 (נא לשים לב שהחלפת את הביטוי ‎:id במזהה שהוחזרת על ידי קריאת ה־OAuth ואת ‎:token באסימון המשתמש)" 22 | oauth2_user_json_url_method: "שיטה שמשמשת לקבלת כתובת ה־JSON של המשתמש" 23 | oauth2_json_user_id_path: "נתיב מזהה המשתמש ב־JSON של ה־OAuth2 של המשתמש. למשל: user.username" 24 | oauth2_json_username_path: "נתיב שם המשתמש ב־JSON של ה־OAuth2 של המשתמש. למשל: user.username" 25 | oauth2_json_name_path: "נתיב ב־JSON משתמש OAuth2 לשם המלא של המשתמש. למשל: user.name.full" 26 | oauth2_json_email_path: "נתיב ב־JSON משתמש OAuth2 לכתובת הדוא״ל של המשתמש. למשל: user.email" 27 | oauth2_json_email_verified_path: "נתיב למצב אימות כתובת הדוא״ל של המשתמש ב־JSON של ה־OAuth2 של המשתמש. למשל: user.email.verified.‏ oauth2_email_verified חייב להיות מושבת כדי שההגדרה הזו תהיה בתוקף" 28 | oauth2_json_avatar_path: "נתיב כתובת התמונה הייצוגית של המשתמש ב־JSON של ה־OAuth2 של המשתמש. למשל: user.avatar_url" 29 | oauth2_email_verified: "נא לבדוק אם אתר זה עם OAuth2 אימת את הדוא״ל" 30 | oauth2_overrides_email: "לעקוף את הדוא״ל של Discourse בדוא״ל חיצוני בכל כניסה למערכת. עובד כמו ההגדרה `auth_overrides_email` (אימות עוקף דוא״ל), אך הוא משמש נקודתית לכניסה עם OAuth2." 31 | oauth2_send_auth_header: "שליחת פרטי גישה של לקוח בכותרת אימות (Authorization) של HTTP" 32 | oauth2_send_auth_body: "שליחת פרטי גישה של לקוח בגוף הבקשה" 33 | oauth2_debug_auth: "לכלול פירוט עשיר לטובת ניפוי שגיאות ביומנים שלך" 34 | oauth2_authorize_options: "בעת בקשת אימות האפשרויות האלו" 35 | oauth2_scope: "בעת בקשת אימות תחום זה" 36 | oauth2_button_title: "הטקסט לכפתור ה־OAuth2" 37 | oauth2_allow_association_change: לאפשר למשתמשים לנתק ולחבר מחדש את חשבונות ה־Discourse שלהם מספק ה־OAuth2 38 | oauth2_disable_csrf: "השבתת בדיקת CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path חייב להיות נוכח לטובת נטרול של oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.sv.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | sv: 8 | login: 9 | authenticator_error_fetch_user_details: "Det gick inte att hämta dina användaruppgifter. Har du ett aktivt konto?" 10 | site_settings: 11 | oauth2_enabled: "Anpassad OAuth2 är aktiverad" 12 | oauth2_client_id: "Klient-ID för anpassad OAuth2" 13 | oauth2_client_secret: "Klienthemlighet för anpassad OAuth2" 14 | oauth2_authorize_url: "Autoriserings-URL för OAuth2" 15 | oauth2_authorize_signup_url: '(valfritt) Alternativ auktoriserings-URL som används när knappen "Registrera dig" används' 16 | oauth2_token_url: "Bevis-URL för OAuth2" 17 | oauth2_token_url_method: "Metod som används för att hämta bevis-URL" 18 | oauth2_callback_user_id_path: "Sökväg i bevissvaret på användar-ID. t.ex. params.info.uuid" 19 | oauth2_callback_user_info_paths: "Sökvägar i bevissvaret på andra användaregenskaper. Egenskaper som stöds är namn, användarnamn, e-postadress, verifierad e-postadress och avatar. Formatet är egenskap:sökväg, t.ex. name:params.info.name" 20 | oauth2_fetch_user_details: "Hämta användarens JSON för OAuth2" 21 | oauth2_user_json_url: "URL för att hämta användarens JSON för OAuth2 (observera att vi ersätter :id med det ID som returneras av OAuth-anrop och :token med bevisets ID)" 22 | oauth2_user_json_url_method: "Metod som används för att hämta användarens JSON-URL" 23 | oauth2_json_user_id_path: "Sökväg i OAuth2-användarens JSON till användar-ID:et, t.ex.: user.id" 24 | oauth2_json_username_path: "Sökväg i OAuth2-användarens JSON till användarnamnet, t.ex. user.username" 25 | oauth2_json_name_path: "Sökväg i OAuth2-användarens JSON till användarens fullständiga namn: user.name.full" 26 | oauth2_json_email_path: "Sökväg i OAuth2-användarens JSON till användarens e-postadress: user.email" 27 | oauth2_json_email_verified_path: "Sökväg i OAuth2-användarens JSON till verifieringsstatus för användarens e-postadress: user.email.verified. oauth2_email_verified måste ha inaktiverats för att den här inställningen ska ha någon verkan" 28 | oauth2_json_avatar_path: "Sökväg i Oauth2-användaren JSON till användarens avatar: user.avatar_url" 29 | oauth2_email_verified: "Kontrollera detta om OAuth2-webbplatsen har verifierat e-postadressen" 30 | oauth2_overrides_email: "Skriv över Discourse e-postadressen med externa e-postadressen vid varje inloggning. Fungerar precis som inställningen `auth_overrides_email` men är specifik för OAuth2-inloggningar." 31 | oauth2_send_auth_header: "Skicka klientbehörighet i rubriken för HTTP-auktorisation" 32 | oauth2_send_auth_body: "Skicka klientbehörighet i begärans meddelandetext" 33 | oauth2_debug_auth: "Omfatta utförlig felsökningsinformation i dina loggar" 34 | oauth2_authorize_options: "Begär dessa alternativ vid auktorisering" 35 | oauth2_scope: "Begär detta omfång vid auktorisering" 36 | oauth2_button_title: "Texten för OAuth2-knappen" 37 | oauth2_allow_association_change: Låt användarna frånkoppla och ansluta sina Discourse-konton igen från OAuth2-leverantören 38 | oauth2_disable_csrf: "Inaktivera CSRF-kontroll" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path måste vara närvarande för att inaktivera oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.ar.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ar: 8 | login: 9 | authenticator_error_fetch_user_details: "تعذَّر استرداد تفاصيل المستخدم الخاصة بك. هل لديك حساب نشط؟" 10 | site_settings: 11 | oauth2_enabled: "تم تفعيل مصادقة OAuth2 المخصَّصة" 12 | oauth2_client_id: "مُعرِّف العميل لمصادقة OAuth2 المخصَّصة" 13 | oauth2_client_secret: "سر العميل لمصادقة OAuth2 المخصَّصة" 14 | oauth2_authorize_url: "عنوان URL للمصادقة لمصادقة OAuth2" 15 | oauth2_authorize_signup_url: 'عنوان URL للمصادقة البديلة (اختياري) المستخدم عند استخدام الزر "تسجيل"' 16 | oauth2_token_url: "عنوان URL للرمز المميَّز لمصادقة OAuth2" 17 | oauth2_token_url_method: "الطريقة المستخدمة لجلب عنوان URL للرمز المميَّز" 18 | oauth2_callback_user_id_path: "المسار في استجابة الرمز المميَّز لمُعرِّف المستخدم. على سبيل المثال: params.info.uuid" 19 | oauth2_callback_user_info_paths: "المسارات في استجابة الرمز المميَّز لخصائص المستخدم الأخرى. الخصائص المدعومة هي name وusername وemail وemail_verified وavatar. التنسيق هو property:path، على سبيل المثال: name:params.info.name" 20 | oauth2_fetch_user_details: "جلب ملف JSON للمستخدم لمصادقة OAuth2" 21 | oauth2_user_json_url: "عنوان URL لجلب ملف JSON للمستخدم لمصادقة OAuth2 (لاحظ أننا استبدلنا :id بالمُعرِّف الذي تم إرجاعه من قِبل استدعاء OAuth و:token بمُعرِّف الرمز المميَّز)" 22 | oauth2_user_json_url_method: "الطريقة المستخدمة لجلب عنوان URL لملف JSON" 23 | oauth2_json_user_id_path: "المسار في ملف JSON للمستخدم لمصادقة OAuth2 إلى مُعرِّف المستخدم. على سبيل المثال: user.id" 24 | oauth2_json_username_path: "المسار في ملف JSON للمستخدم لمصادقة OAuth2. على سبيل المثال: user.username" 25 | oauth2_json_name_path: "المسار في ملف JSON للمستخدم لمصادقة OAuth2 إلى اسم المستخدم الكامل. على سبيل المثال: user.name.full" 26 | oauth2_json_email_path: "المسار في ملف JSON للمستخدم لمصادقة OAuth2 إلى البريد الإلكتروني للمستخدم. على سبيل المثال: user.email" 27 | oauth2_json_email_verified_path: "المسار في ملف JSON للمستخدم لمصادقة OAuth2 إلى حالة التحقُّق من البريد الإلكتروني للمستخدم. على سبيل المثال: user.email.verified. يجب إيقاف oauth2_email_verified لهذا الإعداد ليحظى بأي تأثير" 28 | oauth2_json_avatar_path: "المسار في ملف JSON للمستخدم لمصادقة OAuth2 إلى الصورة الرمزية للمستخدم. على سبيل المثال: user.avatar_url" 29 | oauth2_email_verified: "تحقَّق من هذا إذا كان موقع OAuth2 قد تحقَّق من البريد الإلكتروني" 30 | oauth2_overrides_email: "استبدال البريد الإلكتروني لـ Discourse بالبريد الإلكتروني البعيد في كل عملية تسجيل دخول. يعمل بإعداد `auth_overrides_email` نفسه، لكنه خاص بعمليات تسجيل الدخول من خلال OAuth2." 31 | oauth2_send_auth_header: "إرسال بيانات اعتماد العميل في رأس مصادقة HTTP" 32 | oauth2_send_auth_body: "إرسال بيانات اعتماد العميل في نص الطلب" 33 | oauth2_debug_auth: "تضمين معلومات تصحيح الأخطاء المنسَّقة في سجلاتك" 34 | oauth2_authorize_options: "طلب الخيارات التالية عند المصادقة" 35 | oauth2_scope: "طلب هذا المجال عند المصادقة" 36 | oauth2_button_title: "نص زر OAuth2" 37 | oauth2_allow_association_change: السماح للمستخدمين بإلغاء ربط حسابات Discourse الخاصة بهم وإعادة ربطها من مقدِّم خدمة OAuth2 38 | oauth2_disable_csrf: "إيقاف فحص CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "يجب أن يكون oauth2_callback_user_id_path موجودًا لإيقاف oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.tr_TR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | tr_TR: 8 | login: 9 | authenticator_error_fetch_user_details: "Kullanıcı ayrıntılarınız görüntülenemedi. Aktif bir hesabınız var mı?" 10 | site_settings: 11 | oauth2_enabled: "Özel OAuth2 etkin" 12 | oauth2_client_id: "Özel OAuth2 için müşteri kimliği" 13 | oauth2_client_secret: "Özel OAuth2 için İstemci Sırrı" 14 | oauth2_authorize_url: "OAuth2 için yetkilendirme URL'si" 15 | oauth2_authorize_signup_url: '(isteğe bağlı) "Kaydol" düğmesi kullanıldığında kullanılan alternatif yetkilendirme URL''si' 16 | oauth2_token_url: "OAuth2 için Token URL'si" 17 | oauth2_token_url_method: "Token URL'sini getirmek için kullanılan yöntem" 18 | oauth2_callback_user_id_path: "Token yanıtında kullanıcı kimliğine giden yol. ör.: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Token yanıtındaki diğer kullanıcı özelliklerine giden yollar. Desteklenen özellikler name, username, email, email_verified ve avatar'dır. Biçim özellik:yol şeklindedir, ör.: name:params.info.name" 20 | oauth2_fetch_user_details: "OAuth2 için kullanıcı JSON'unu getir" 21 | oauth2_user_json_url: "OAuth2 için kullanıcı JSON'unu alma URL'si (:id'yi OAuth çağrısı tarafından döndürülen id ile ve :token'ı token id ile değiştirdiğimize dikkat edin)" 22 | oauth2_user_json_url_method: "Kullanıcı JSON URL'sini getirmek için kullanılan yöntem" 23 | oauth2_json_user_id_path: "OAuth2 Kullanıcı JSON'unda kullanıcı kimliğine giden yol. ör.: user.id" 24 | oauth2_json_username_path: "OAuth2 Kullanıcı JSON'unda kullanıcı adına giden yol. ör.: user.username" 25 | oauth2_json_name_path: "OAuth2 Kullanıcı JSON'unda kullanıcının tam adına giden yol. ör.: user.name.full" 26 | oauth2_json_email_path: "OAuth2 Kullanıcı JSON'unda kullanıcının e-postasına giden yol. ör.: user.email" 27 | oauth2_json_email_verified_path: "OAuth2 Kullanıcı JSON'unda kullanıcının e-posta doğrulama durumuna giden yol. ör.: user.email.verified. oauth2_email_verified, bu ayarın herhangi bir etkiye sahip olması için devre dışı bırakılmalıdır" 28 | oauth2_json_avatar_path: "Oauth2 Kullanıcı JSON'unda kullanıcının avatarına giden yol. ör.: user.avatar_url" 29 | oauth2_email_verified: "OAuth2 sitesi e-postayı doğruladıysa bunu kontrol edin" 30 | oauth2_overrides_email: "Her oturum açma işleminde Discourse e-postasını uzak e-posta ile geçersiz kılın. \"auth_overrides_email\" ayarı ile aynı şekilde çalışır, ancak OAuth2 girişlerine özeldir." 31 | oauth2_send_auth_header: "İstemci kimlik bilgilerini HTTP Yetkilendirme üstbilgisinde gönderin" 32 | oauth2_send_auth_body: "İstemci kimlik bilgilerini talep gövdesinde gönderin" 33 | oauth2_debug_auth: "Günlüklerinize zengin hata ayıklama bilgileri ekleyin" 34 | oauth2_authorize_options: "Yetkilendirirken bu seçenekleri isteyin" 35 | oauth2_scope: "Yetkilendirirken bu kapsamı isteyin" 36 | oauth2_button_title: "OAuth2 düğmesinin metni" 37 | oauth2_allow_association_change: Kullanıcıların Discourse hesaplarının bağlantısını OAuth2 sağlayıcısından kesmelerine ve yeniden bağlamalarına izin verin 38 | oauth2_disable_csrf: "CSRF kontrolünü devre dışı bırakın" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_fetch_user_details'ı devre dışı bırakmak için oauth2_callback_user_id_path mevcut olmalıdır" 41 | -------------------------------------------------------------------------------- /config/locales/server.it.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | it: 8 | login: 9 | authenticator_error_fetch_user_details: "Impossibile recuperare i tuoi dettagli utente. Hai un account attivo?" 10 | site_settings: 11 | oauth2_enabled: "OAuth2 personalizzato abilitato" 12 | oauth2_client_id: "ID client per OAuth2 personalizzato" 13 | oauth2_client_secret: "Segreto client per OAuth2 personalizzato" 14 | oauth2_authorize_url: "URL di autorizzazione per OAuth2" 15 | oauth2_authorize_signup_url: '(facoltativo) URL di autorizzazione alternativo utilizzato quando si usa il pulsante "Registrati"' 16 | oauth2_token_url: "URL del token per OAuth2" 17 | oauth2_token_url_method: "Metodo utilizzato per recuperare l'URL del token" 18 | oauth2_callback_user_id_path: "Percorso nella risposta del token all'id utente. es: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Percorsi nella risposta del token alle altre proprietà utente. Le proprietà supportate sono name, username, email, email_verified e avatar. Il formato è property:path, es: name:params.info.name" 20 | oauth2_fetch_user_details: "Recupera il JSON dell'utente per OAuth2" 21 | oauth2_user_json_url: "URL per recuperare il JOSN dell'utente per OAuth2 (nota: sostituiamo :id con l'id restituito dalla chiamata OAuth e :token con l'id token)" 22 | oauth2_user_json_url_method: "Metodo utilizzato per recuperare l'URL JSON dell'utente" 23 | oauth2_json_user_id_path: "Percorso nel JSON dell'utente OAuth2 per l'id utente. es.: user.id" 24 | oauth2_json_username_path: "Percorso nel JSON dell'utente OAuth2 per il nome utente. es.: user.username" 25 | oauth2_json_name_path: "Percorso nel JSON dell'utente OAuth2 per il nome completo. es.: user.name.full" 26 | oauth2_json_email_path: "Percorso nel JSON dell'utente OAuth2 per l'email dell'utente. es.: user.email" 27 | oauth2_json_email_verified_path: "Percorso nel JSON dell'utente OAuth2 per lo stato di verifica dell'email utente. Es.: user.email.verified. oauth2_email_verified deve essere disabilitato affinché questa impostazione abbia effetto." 28 | oauth2_json_avatar_path: "Percorso nel JSON dell'utente OAuth2 per l'avatar dell'utente. es.: user.avatar_url" 29 | oauth2_email_verified: "Abilita questa impostazione se il sito OAuth2 ha verificato \nl'email" 30 | oauth2_overrides_email: "Sostituisci l'e-mail di Discourse con l'e-mail remota a ogni accesso. Funziona come l'impostazione `auth_overrides_email`, ma è specifica per gli accessi OAuth2." 31 | oauth2_send_auth_header: "Invia le credenziali del client in un'intestazione di autorizzazione HTTP" 32 | oauth2_send_auth_body: "Invia le credenziali del client nel corpo della richiesta" 33 | oauth2_debug_auth: "Includi informazioni di debugging complete nei tuoi log" 34 | oauth2_authorize_options: "In fase di autorizzazione, richiedi queste opzioni" 35 | oauth2_scope: "In fase di autorizzazione, richiedi questo ambito" 36 | oauth2_button_title: "Il testo per il pulsante OAuth2" 37 | oauth2_allow_association_change: Consenti agli utenti di disconnettere e riconnettere i loro account Discourse dal fornitore OAuth2 38 | oauth2_disable_csrf: "Disabilita il controllo CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path deve essere presente per disabilitare oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.fi.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fi: 8 | login: 9 | authenticator_error_fetch_user_details: "Käyttäjätietojasi ei löytynyt. Oletko varma, että tilisi on aktiivinen?" 10 | site_settings: 11 | oauth2_enabled: "Mukautettu OAuth2 on käytössä" 12 | oauth2_client_id: "Mukautetun OAuth2:n asiakastunnus" 13 | oauth2_client_secret: "Mukautetun OAuth2:n asiakkaan salatunnus" 14 | oauth2_authorize_url: "OAuth2:n valtuutuksen URL-osoite" 15 | oauth2_authorize_signup_url: '(valinnainen) Vaihtoehtoinen valtuutus-URL, jota käytetään, kun Rekisteröidy-painiketta käytetään' 16 | oauth2_token_url: "OAuth2:n tunnuksen URL-osoite" 17 | oauth2_token_url_method: "Tunnuksen URL-osoitteen hakemiseen käytetty menetelmä" 18 | oauth2_callback_user_id_path: "Polku tunnuksen vastauksessa käyttäjätunnukseen. esim.: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Polut tunnuksen vastauksessa muille käyttäjän ominaisuuksille. Tuetut ominaisuudet ovat name, username, email, email_verified ja avatar. Muoto on ominaisuus:polku, esim.: name:params.info.name" 20 | oauth2_fetch_user_details: "Hae käyttäjän JSON OAuth2:lle" 21 | oauth2_user_json_url: "URL-osoite käyttäjän JSON:n hakemiseksi OAuth2:ta varten (huomaa, että korvaamme :id:n OAuth-kutsun palauttamalla id-tunnuksella ja :tokenin token-tunnuksella)" 22 | oauth2_user_json_url_method: "Käyttäjän JSON:n URL-osoitteen hakemiseen käytetty menetelmä" 23 | oauth2_json_user_id_path: "Polku OAuth2:n käyttäjän JSON:ssä käyttäjätunnukseen. esim.: user.id" 24 | oauth2_json_username_path: "Polku OAuth2:n käyttäjän JSON:ssä käyttäjänimeen. esim.: user.username" 25 | oauth2_json_name_path: "Polku OAuth2:n käyttäjän JSON:ssä käyttäjän koko nimeen. esim.: user.name.full" 26 | oauth2_json_email_path: "Polku OAuth2:n käyttäjän JSON:ssä käyttäjän sähköpostiosoitteeseen. esim.: user.email" 27 | oauth2_json_email_verified_path: "Polku OAuth2:n käyttäjän JSON:ssä käyttäjän sähköpostin vahvistustilaan. Esim.: user.email.verified. oauth2_email_verified täytyy poistaa käytöstä, jotta tällä asetuksella olisi vaikutusta." 28 | oauth2_json_avatar_path: "Polku OAuth2:n käyttäjän JSON:ssä käyttäjän avatariin. esim.: user.avatar_url" 29 | oauth2_email_verified: "Tarkasta, onko tämä OAuth2 sivusto varmistanut sähköpostin" 30 | oauth2_overrides_email: "Ohita Discoursen sähköpostiosoite etäsähköpostilla jokaisen kirjautumisen yhteydessä. Toimii samalla tavalla kuin `auth_overrides_email`-asetus, mutta koskee OAuth2-kirjautumisia." 31 | oauth2_send_auth_header: "Lähetä asiakkaan tunnistetiedot HTTP Authorization -otsikkotiedoissa" 32 | oauth2_send_auth_body: "Lähetä asiakkaan tunnistetiedot pyynnön tekstiosassa" 33 | oauth2_debug_auth: "Sisällytä lokeihin laajat virheenkorjaustiedot" 34 | oauth2_authorize_options: "Pyydä näitä vaihtoehtoja valtuutuksen yhteydessä" 35 | oauth2_scope: "Pyydä tätä aluetta valtuutuksen yhteydessä" 36 | oauth2_button_title: "Teksti OAuth2-painiketta varten" 37 | oauth2_allow_association_change: Salli käyttäjien yhdistää Discourse-tilinsä OAuth2-palveluntarjoajaan ja katkaista niiden yhteys 38 | oauth2_disable_csrf: "Poista CSRF-tarkistus käytöstä" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path täytyy olla määritetty, jotta oauth2_fetch_user_details voidaan poistaa käytöstä" 41 | -------------------------------------------------------------------------------- /config/locales/server.ru.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | ru: 8 | login: 9 | authenticator_error_fetch_user_details: "Не удалось получить данные пользователя. У вас есть активный аккаунт?" 10 | site_settings: 11 | oauth2_enabled: "Пользовательский OAuth2 включен" 12 | oauth2_client_id: "Идентификатор клиента для пользовательского OAuth2" 13 | oauth2_client_secret: "Секрет клиента для пользовательских OAuth2" 14 | oauth2_authorize_url: "URL авторизации для OAuth2" 15 | oauth2_authorize_signup_url: '(необязательно) Альтернативный URL-адрес авторизации, используемый при задействовании кнопки ''Зарегистрироваться''' 16 | oauth2_token_url: "URL токена для OAuth2" 17 | oauth2_token_url_method: "Метод, используемый для получения URL токена" 18 | oauth2_callback_user_id_path: "Путь в ответе токена к идентификатору пользователя. например: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Пути в ответе токена к другим параметрам пользователя. Поддерживаемые параметры: name, username, email, email_verified и avatar. Формат указывается в виде 'свойство: путь', например: name:params.info.name" 20 | oauth2_fetch_user_details: "Получить USER JSON для OAuth2" 21 | oauth2_user_json_url: "URL для получения USER JSON для OAuth2 (обратите внимание, мы заменяем: id на идентификатор, возвращаемый вызовом OAuth, и :token - идентификатором токена)" 22 | oauth2_user_json_url_method: "Метод, используемый для получения USER URL JSON" 23 | oauth2_json_user_id_path: "Путь в OAuth2 User JSON к идентификатору пользователя. например: user.id" 24 | oauth2_json_username_path: "Путь в OAuth2 User JSON к имени пользователя. например: user.username" 25 | oauth2_json_name_path: "Путь в OAuth2 User JSON к полному имени пользователя. Например: user.name.full" 26 | oauth2_json_email_path: "Путь в OAuth2 User JSON к электронной почте пользователя. например: user.email" 27 | oauth2_json_email_verified_path: "Путь в OAuth2 User JSON к состоянию проверки электронной почты пользователя. Например: user.email.verified. oauth2_email_verified должен быть отключен, чтобы этот параметр имел какой-либо эффект" 28 | oauth2_json_avatar_path: "Путь в Oauth2 User JSON к аватару пользователя. например: user.avatar_url" 29 | oauth2_email_verified: "Включите эту настройку, если OAuth2-сайт подтвердил адрес электронной почты." 30 | oauth2_overrides_email: "Заменять электронную почту Discourse удалённой электронной почтой при каждом входе в систему. Работает так же, как параметр `auth_overrides_email`, но только при входе в систему через OAuth2." 31 | oauth2_send_auth_header: "Отправлять учетные данные клиента в заголовке HTTP-запроса" 32 | oauth2_send_auth_body: "Отправлять учетные данные клиента в теле запроса" 33 | oauth2_debug_auth: "Добавлять в журнал расширенную отладочную информацию" 34 | oauth2_authorize_options: "При авторизации запрашивать эти параметры" 35 | oauth2_scope: "При авторизации запрашивать эту область" 36 | oauth2_button_title: "Текст для кнопки 'OAuth2'" 37 | oauth2_allow_association_change: Разрешить пользователям отключать и повторно подключать свои учётные записи Discourse от поставщика OAuth2 38 | oauth2_disable_csrf: "Отключить проверку CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "Для отключения 'oauth2_fetch_user_details' должен быть настроен параметр 'oauth2_callback_user_id_path'" 41 | -------------------------------------------------------------------------------- /config/locales/server.nl.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | nl: 8 | login: 9 | authenticator_error_fetch_user_details: "Kon je gebruikersgegevens niet ophalen. Heb je een actief account?" 10 | site_settings: 11 | oauth2_enabled: "Aangepaste OAuth2 is ingeschakeld" 12 | oauth2_client_id: "Client-ID voor aangepaste OAuth2" 13 | oauth2_client_secret: "Clientgeheim voor aangepaste OAuth2" 14 | oauth2_authorize_url: "Autorisatie-URL voor OAuth2" 15 | oauth2_authorize_signup_url: '(optioneel) Alternatieve autorisatie-URL die wordt gebruikt wanneer de knop "Registreren" wordt gebruikt' 16 | oauth2_token_url: "Token-URL voor OAuth2" 17 | oauth2_token_url_method: "Gebruikte methode voor ophalen van de token-URL" 18 | oauth2_callback_user_id_path: "Pad in het tokenantwoord naar de gebruikers-ID, bijvoorbeeld params.info.uuid" 19 | oauth2_callback_user_info_paths: "Paden in het tokenantwoord voor andere gebruikerseigenschappen. Ondersteunde eigenschappen zijn name, username, email, email_verified en avatar. De notatie is property:path, bijvoorbeeld name:params.info.name" 20 | oauth2_fetch_user_details: "Gebruikers-JSON voor OAuth2 ophalen" 21 | oauth2_user_json_url: "URL voor het ophalen van de gebruikers-JSON voor OAuth2 (we vervangen :id vervangen door de geretourneerde ID van de OAuth-aanroep en :token door de token-ID)" 22 | oauth2_user_json_url_method: "Gebruikte methode voor ophalen van de gebruikers-JSON" 23 | oauth2_json_user_id_path: "Pad in de OAuth2-gebruikers-JSON naar de gebruikers-ID, bijvoorbeeld user.id" 24 | oauth2_json_username_path: "Pad in de OAuth2-gebruikers-JSON naar de gebruikersnaam, bijvoorbeeld user.username" 25 | oauth2_json_name_path: "Pad in de OAuth2-gebruikers-JSON naar de volledige naam van de gebruiker, bijvoorbeeld user.name.full" 26 | oauth2_json_email_path: "Pad in de OAuth2-gebruikers-JSON naar het e-mailadres van de gebruiker, bijvoorbeeld user.email" 27 | oauth2_json_email_verified_path: "Pad in de OAuth2-gebruikers-JSON naar de e-mailverificatiestatus van de gebruiker, bijvoorbeeld user.email.verified. Deze instelling heeft alleen effect als oauth2_email_verified is uitgeschakeld" 28 | oauth2_json_avatar_path: "Pad in de Oauth2-gebruikers-JSON naar de avatar van de gebruiker, bijvoorbeeld user.avatar_url" 29 | oauth2_email_verified: "Controleer dit als de OAuth2-site het e-mailadres heeft geverifieerd" 30 | oauth2_overrides_email: "Overschrijf het Discourse-e-mailadres met het externe e-mailadres bij elke aanmelding. Werkt hetzelfde als de instelling `auth_overrides_email`, maar is specifiek voor OAuth2-aanmeldingen." 31 | oauth2_send_auth_header: "Clientaanmeldgegevens sturen in een HTTP-autorisatieheader" 32 | oauth2_send_auth_body: "Clientaanmeldgegevens sturen in verzoektekst" 33 | oauth2_debug_auth: "Uitgebreide debuggegevens opnemen in je logs" 34 | oauth2_authorize_options: "Deze opties verzoeken bij autoriseren" 35 | oauth2_scope: "Dit bereik verzoeken bij autoriseren" 36 | oauth2_button_title: "De tekst voor de OAuth2-knop" 37 | oauth2_allow_association_change: Gebruikers toestaan hun Discourse-account te ontkoppelen van de OAuth2-provider en opnieuw te koppelen 38 | oauth2_disable_csrf: "CSRF-controle uitschakelen" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path moet aanwezig zijn om oauth2_fetch_user_details uit te schakelen" 41 | -------------------------------------------------------------------------------- /config/locales/server.de.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | de: 8 | login: 9 | authenticator_error_fetch_user_details: "Deine Benutzerdaten konnten nicht abgerufen werden. Hast du ein aktives Konto?" 10 | site_settings: 11 | oauth2_enabled: "Benutzerdefiniertes OAuth2 ist aktiviert" 12 | oauth2_client_id: "Client-ID für benutzerdefiniertes OAuth2" 13 | oauth2_client_secret: "Client-Geheimnis für benutzerdefiniertes OAuth2" 14 | oauth2_authorize_url: "Autorisierungs-URL für OAuth2" 15 | oauth2_authorize_signup_url: '(optional) Alternative Autorisierungs-URL, die zum Einsatz kommt, wenn die Schaltfläche „Registrieren“ verwendet wird' 16 | oauth2_token_url: "Token-URL für OAuth2" 17 | oauth2_token_url_method: "Methode, mit der die Token-URL abgerufen wird" 18 | oauth2_callback_user_id_path: "Pfad in der Token-Antwort zur Benutzer-ID. Beispiel: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Pfade in der Token-Antwort zu anderen Benutzereigenschaften. Unterstützte Eigenschaften sind name, username, email, email_verified und avatar. Format: property:path, z. B. name:params.info.name" 20 | oauth2_fetch_user_details: "Benutzer-JSON für OAuth2 abrufen" 21 | oauth2_user_json_url: "URL zum Abrufen der Benutzer-JSON für OAuth2 (beachte, dass wir :id durch die vom OAuth-Call zurückgegebene ID und :token durch die Token-ID ersetzen)" 22 | oauth2_user_json_url_method: "Methode, mit der die Benutzer-JSON-URL abgerufen wird" 23 | oauth2_json_user_id_path: "Pfad im OAuth2-Benutzer-JSON zur Benutzer-ID. Beispiel: user.id" 24 | oauth2_json_username_path: "Pfad im OAuth2-Benutzer-JSON zum Benutzernamen. Beispiel: user.username" 25 | oauth2_json_name_path: "Pfad im OAuth2-Benutzer-JSON zum vollständigen Namen des Benutzers. Beispiel: user.name.full" 26 | oauth2_json_email_path: "Pfad im OAuth2-Benutzer-JSON zur E-Mail-Adresse des Benutzers. Beispiel: user.email" 27 | oauth2_json_email_verified_path: "Pfad im OAuth2-Benutzer-JSON zum E-Mail-Verifizierungsstatus des Benutzers. Beispiel: user.email.verified. oauth2_email_verified muss deaktiviert sein, damit diese Einstellung eine Wirkung hat" 28 | oauth2_json_avatar_path: "Pfad im OAuth2-Benutzer-JSON zum Avatar des Benutzers. Beispiel: user.avatar_url" 29 | oauth2_email_verified: "Aktivieren, wenn die OAuth2-Website die E-Mail verifiziert hat" 30 | oauth2_overrides_email: "Überschreibt die Discourse-E-Mail-Adresse bei jeder Anmeldung mit der remote E-Mail-Adresse. Funktioniert genauso wie die Einstellung `auth_overrides_email`, ist aber spezifisch für OAuth2-Anmeldungen." 31 | oauth2_send_auth_header: "Client-Anmeldedaten in einem HTTP-Autorisierungs-Header senden" 32 | oauth2_send_auth_body: "Client-Anmeldedaten im Anfrage-Body senden" 33 | oauth2_debug_auth: "Ausführliche Informationen zur Fehlerbehebung in Protokolle aufnehmen" 34 | oauth2_authorize_options: "Bei der Autorisierung folgende Optionen anfordern" 35 | oauth2_scope: "Bei der Autorisierung folgenden Bereich anfordern" 36 | oauth2_button_title: "Der Text für die OAuth2-Schaltfläche" 37 | oauth2_allow_association_change: Erlaube Benutzern, ihre Discourse-Konten vom OAuth2-Anbieter zu trennen und wieder zu verbinden 38 | oauth2_disable_csrf: "CSRF-Prüfung deaktivieren" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path muss vorhanden sein, um oauth2_fetch_user_details zu deaktivieren" 41 | -------------------------------------------------------------------------------- /config/locales/server.pt_BR.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | pt_BR: 8 | login: 9 | authenticator_error_fetch_user_details: "Não foi possível recuperar os detalhes do(a) usuário(a). Você tem uma conta ativa?" 10 | site_settings: 11 | oauth2_enabled: "OAuth2 Personalizado está ativado" 12 | oauth2_client_id: "ID do cliente para o OAuth2 personalizado" 13 | oauth2_client_secret: "Segredo do cliente para o OAuth2 personalizado" 14 | oauth2_authorize_url: "URL de autorização para o OAuth2" 15 | oauth2_authorize_signup_url: '(opcional) URL de autorização alternativa usada quando o botão “Inscrever-se” é usado' 16 | oauth2_token_url: "URL do token para o OAuth2" 17 | oauth2_token_url_method: "Método usado para buscar a URL do token" 18 | oauth2_callback_user_id_path: "Caminho no JSON do(a) Usuário(a) do OAuth2 para a ID do(a) usuário(a). ex: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Caminhos na resposta do token para outras propriedades do(a) usuário(a). As propriedades suportadas são nome, nome do(a) usuário(a), e-mail, email_verified e avatar. O formato é propriedade: caminho. Por exemplo: name:params.info.name" 20 | oauth2_fetch_user_details: "Buscar JSON do(a) usuário(a) para OAuth2" 21 | oauth2_user_json_url: "URL para buscar o JSON do(a) usuário(a) para o OAuth2 (observe que substituímos :id pela id retornada pela chamada OAuth e :token pela id do token)" 22 | oauth2_user_json_url_method: "Método usado para buscar a URL do JSON do(a) usuário(a)" 23 | oauth2_json_user_id_path: "Caminho no JSON do(a) Usuário(a) do OAuth2 para a ID do(a) usuário(a). ex: user.id" 24 | oauth2_json_username_path: "Caminho no JSON do(a) Usuário(a) do OAuth2 para o nome do(a) usuário(a). ex: user.username" 25 | oauth2_json_name_path: "Caminho no JSON do(a) usuário(a) do OAuth2 para o nome do(a) usuário(a). ex: user.name.full" 26 | oauth2_json_email_path: "Caminho no JSON do(a) usuário(a) do OAuth2 para o e-mail do(a) usuário(a). ex: user.email" 27 | oauth2_json_email_verified_path: "Caminho no JSON do(a) usuário(a) do OAuth2 para o estado de verificação do e-mail do(a) usuário(a).,ex: user.email.verified. oauth2_email_verified deve estar desativado para esta configuração ter efeito" 28 | oauth2_json_avatar_path: "Caminho no JSON do(a) usuário(a) do OAuth2 para o avatar do(a) usuário(a). ex: user.avatar_url" 29 | oauth2_email_verified: "Verificar se o site do OAuth2 confirmou o e-mail" 30 | oauth2_overrides_email: "Substitua o e-mail do Discourse pelo e-mail remoto toda vez que entrar. Funciona igual à configuração `auth_overrides_email`, mas é específica para logins do OAuth2" 31 | oauth2_send_auth_header: "Enviar credenciais de cliente em um cabeçalho de autorização do HTTP" 32 | oauth2_send_auth_body: "Enviar credenciais de cliente no corpo da solicitação" 33 | oauth2_debug_auth: "Incluir informações de depuração avançadas em seus registros" 34 | oauth2_authorize_options: "Ao autorizar, solicite estas opções" 35 | oauth2_scope: "Ao autorizar, solicite este escopo" 36 | oauth2_button_title: "O texto para o botão do OAuth2" 37 | oauth2_allow_association_change: Permitir que usuários(as) desconectem e reconectem suas contas do Discourse no provedor do OAuth2 38 | oauth2_disable_csrf: "Desativar verificação CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path deve estar presente para desativar oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.es.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | es: 8 | login: 9 | authenticator_error_fetch_user_details: "No se pudieron recuperar tus datos de usuario. ¿Tienes una cuenta activa?" 10 | site_settings: 11 | oauth2_enabled: "OAuth2 personalizado está habilitado" 12 | oauth2_client_id: "ID de cliente para OAuth2 personalizado" 13 | oauth2_client_secret: "Secreto de cliente para OAuth2 personalizado" 14 | oauth2_authorize_url: "URL de autorización para OAuth2" 15 | oauth2_authorize_signup_url: '(opcional) URL de autorización alternativa utilizada cuando se usa el botón «Registrarse»' 16 | oauth2_token_url: "URL de token para OAuth2" 17 | oauth2_token_url_method: "Método utilizado para obtener la URL del token" 18 | oauth2_callback_user_id_path: "Ruta en la respuesta del token a la identificación del usuario. Ejemplo: params.info.uuid" 19 | oauth2_callback_user_info_paths: "Rutas en la respuesta del token a otras propiedades del usuario. Las propiedades admitidas son nombre, nombre de usuario, correo electrónico, email_verified y avatar. El formato es property:path, por ejemplo: name:params.info.name" 20 | oauth2_fetch_user_details: "Obtener usuario JSON para OAuth2" 21 | oauth2_user_json_url: "URL para obtener el usuario JSON para OAuth2 (ten en cuenta que reemplazamos :id con la id devuelta por OAuth call y :token con la id del token)" 22 | oauth2_user_json_url_method: "Método utilizado para obtener la URL JSON del usuario" 23 | oauth2_json_user_id_path: "Ruta en el JSON del usuario de OAuth2 a la ID del usuario. por ejemplo: user.id" 24 | oauth2_json_username_path: "Ruta en el JSON del usuario de OAuth2 al nombre de usuario. por ejemplo: user.username" 25 | oauth2_json_name_path: "Ruta en el JSON del usuario de OAuth2 al usuario completo: user.name.full" 26 | oauth2_json_email_path: "Ruta en el JSON del usuario de OAuth2 al correo electrónico del usuario: user.email" 27 | oauth2_json_email_verified_path: "Ruta en el JSON de usuario de OAuth2 al estado de verificación de correo electrónico del usuario: user.email.verified. oauth2_email_verified debe estar deshabilitado para que esta configuración tenga efecto" 28 | oauth2_json_avatar_path: "Ruta en el JSON del usuario de Oauth2 al avatar del usuario: user.avatar_url" 29 | oauth2_email_verified: "Marca esto si el sitio OAuth2 ha verificado el correo electrónico" 30 | oauth2_overrides_email: "Sobrescribe el correo electrónico de Discourse con el correo electrónico remoto en cada inicio de sesión. Funciona igual que la configuración `auth_overrides_email`, pero es específica de los inicios de sesión de OAuth2." 31 | oauth2_send_auth_header: "Enviar credenciales de cliente en un encabezado de autorización HTTP" 32 | oauth2_send_auth_body: "Enviar las credenciales del cliente en el cuerpo de la solicitud" 33 | oauth2_debug_auth: "Incluir información abundante de depuración en tus registros" 34 | oauth2_authorize_options: "Al autorizar, solicitar estas opciones" 35 | oauth2_scope: "Al autorizar, solicitar este alcance" 36 | oauth2_button_title: "El texto para el botón OAuth2" 37 | oauth2_allow_association_change: Permitir a los usuarios desconectar y volver a conectar sus cuentas de Discourse del proveedor OAuth2 38 | oauth2_disable_csrf: "Desactivar la comprobación CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "oauth2_callback_user_id_path debe estar presente para deshabilitar oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /config/locales/server.fr.yml: -------------------------------------------------------------------------------- 1 | # WARNING: Never edit this file. 2 | # It will be overwritten when translations are pulled from Crowdin. 3 | # 4 | # To work with us on translations, join this project: 5 | # https://translate.discourse.org/ 6 | 7 | fr: 8 | login: 9 | authenticator_error_fetch_user_details: "Impossible de récupérer vos informations d'utilisateur. Avez-vous un compte actif ?" 10 | site_settings: 11 | oauth2_enabled: "L'option OAuth2 personnalisée est activée" 12 | oauth2_client_id: "ID de client pour l'option OAuth2 personnalisée" 13 | oauth2_client_secret: "Secret du client pour l'option OAuth2 personnalisée" 14 | oauth2_authorize_url: "URL d'autorisation pour l'option OAuth2" 15 | oauth2_authorize_signup_url: '(facultatif) URL d''autorisation alternative utilisée lorsque le bouton « S''inscrire » est utilisé' 16 | oauth2_token_url: "URL du jeton pour l'option OAuth2" 17 | oauth2_token_url_method: "Méthode utilisée pour récupérer l'adresse URL du jeton" 18 | oauth2_callback_user_id_path: "Chemin dans la réponse du jeton vers l'ID utilisateur (p. ex., params.info.uuid)" 19 | oauth2_callback_user_info_paths: "Chemins dans la réponse de jeton vers d'autres propriétés de l'utilisateur. Les propriétés prises en charge sont le nom, le nom d'utilisateur, l'adresse e-mail, l'adresse e-mail vérifiée et l'avatar (name, username, email, email_verified et avatar). Le format est le suivant : property:path (p. ex. : name:params.info.name)" 20 | oauth2_fetch_user_details: "Récupérer le JSON de l'utilisateur pour l'option OAuth2" 21 | oauth2_user_json_url: "URL pour récupérer le JSON de l'utilisateur pour l'option OAuth2 (remarque : nous remplaçons :id par l'identifiant renvoyé par l'appel OAuth et :token par l'identifiant du jeton)." 22 | oauth2_user_json_url_method: "Méthode utilisée pour récupérer l'adresse URL du JSON de l'utilisateur" 23 | oauth2_json_user_id_path: "Chemin dans le JSON de l'utilisateur OAuth2 vers l'ID utilisateur (p. ex., user.id)" 24 | oauth2_json_username_path: "Chemin dans le JSON de l'utilisateur OAuth2 vers le nom d'utilisateur (p. ex., user.username)" 25 | oauth2_json_name_path: "Chemin dans le JSON de l'utilisateur OAuth2 vers le nom complet de l'utilisateur (p. ex., user.name.full)" 26 | oauth2_json_email_path: "Chemin dans le JSON de l'utilisateur OAuth2 vers l'adresse e-mail de l'utilisateur (p. ex., user.email)" 27 | oauth2_json_email_verified_path: "Chemin dans le JSON de l'utilisateur OAuth2 vers l'état de vérification de l'adresse e-mail de l'utilisateur (p. ex., user.email.verified). L'attribut oauth2_email_verified doit être désactivé pour que ce paramètre prenne effet." 28 | oauth2_json_avatar_path: "Chemin dans le JSON de l'utilisateur OAuth2 vers l'avatar de l'utilisateur (p. ex., user.avatar_url)" 29 | oauth2_email_verified: "Cochez cette case si le site OAuth2 a vérifié l'adresse e-mail" 30 | oauth2_overrides_email: "Remplacez l'adresse e-mail Discourse par l'adresse e-mail distante à chaque connexion. Fonctionne de la même manière que le paramètre « auth_overrides_email », mais reste spécifique aux connexions OAuth2." 31 | oauth2_send_auth_header: "Envoyer les informations d'identification du client dans un en-tête d'autorisation HTTP" 32 | oauth2_send_auth_body: "Envoyer les informations d'identification du client dans le corps de la requête" 33 | oauth2_debug_auth: "Inclure des informations de débogage riches dans vos journaux" 34 | oauth2_authorize_options: "Lors de l'autorisation, demander ces options" 35 | oauth2_scope: "Lors de l’autorisation, demander cette permission" 36 | oauth2_button_title: "Le texte du bouton OAuth2" 37 | oauth2_allow_association_change: Autoriser les utilisateurs à déconnecter et à reconnecter leurs comptes Discourse du fournisseur OAuth2 38 | oauth2_disable_csrf: "Désactiver la vérification CSRF" 39 | errors: 40 | oauth2_fetch_user_details: "Le paramètre oauth2_callback_user_id_path doit être présent pour désactiver oauth2_fetch_user_details" 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## discourse-oauth2-basic 2 | 3 | > [!IMPORTANT] 4 | > This plugin has now been bundled into Discourse core. See: https://meta.discourse.org/t/bundling-more-popular-plugins-with-discourse-core/373574 5 | 6 | This plugin allows you to use a basic OAuth2 provider as authentication for 7 | Discourse. It should work with many providers, with the caveat that they 8 | must provide a JSON endpoint for retrieving information about the user 9 | you are logging in. 10 | 11 | This is mainly useful for people who are using login providers that aren't 12 | very popular. If you want to use Google, Facebook or Twitter, those are 13 | included out of the box and you don't need this plugin. You can also 14 | look for other login providers in our [Github Repo](https://github.com/discourse). 15 | 16 | ## Usage 17 | 18 | ## Part 1: Basic Configuration 19 | 20 | First, set up your Discourse application remotely on your OAuth2 provider. 21 | It will require a **Redirect URI** which should be: 22 | 23 | `http://DISCOURSE_HOST/auth/oauth2_basic/callback` 24 | 25 | Replace `DISCOURSE_HOST` with the appropriate value, and make sure you are 26 | using `https` if enabled. The OAuth2 provider should supply you with a 27 | client ID and secret, as well as a couple of URLs. 28 | 29 | Visit your **Admin** > **Settings** > **OAuth2 Login** and fill in the basic 30 | configuration for the OAuth2 provider: 31 | 32 | - `oauth2_enabled` - check this off to enable the feature 33 | 34 | - `oauth2_client_id` - the client ID from your provider 35 | 36 | - `oauth2_client_secret` - the client secret from your provider 37 | 38 | - `oauth2_authorize_url` - your provider's authorization URL 39 | 40 | - `oauth2_token_url` - your provider's token URL. 41 | 42 | If you can't figure out the values for the above settings, check the 43 | developer documentation from your provider or contact their customer 44 | support. 45 | 46 | ## Part 2: Configuring the JSON User Endpoint 47 | 48 | Discourse is now capable of receiving an authorization token from your 49 | OAuth2 provider. Unfortunately, Discourse requires more information to 50 | be able to complete the authentication. 51 | 52 | We require an API endpoint that can be contacted to retrieve information 53 | about the user based on the token. 54 | 55 | For example, the OAuth2 provider [SoundCloud provides such a URL](https://developers.soundcloud.com/docs/api/reference#me). 56 | If you have an OAuth2 token for SoundCloud, you can make a GET request 57 | to `https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN` and 58 | will get back a JSON object containing information on the user. 59 | 60 | To configure this on Discourse, we need to set the value of the 61 | `oauth2_user_json_url` setting. In this case, we'll input the value of: 62 | 63 | ``` 64 | https://api.soundcloud.com/me?oauth_token=:token 65 | ``` 66 | 67 | The part with `:token` tells Discourse that it needs to replace that value 68 | with the authorization token it received when the authentication completed. 69 | Discourse will also add the `Authorization: Bearer` HTTP header with the 70 | token in case your API uses that instead. 71 | 72 | There is one last step to complete. We need to tell Discourse what 73 | attributes are available in the JSON it received. Here's a sample 74 | response from SoundCloud: 75 | 76 | ```json 77 | { 78 | "id": 3207, 79 | "permalink": "jwagener", 80 | "username": "Johannes Wagener", 81 | "uri": "https://api.soundcloud.com/users/3207", 82 | "permalink_url": "http://soundcloud.com/jwagener", 83 | "avatar_url": "http://i1.sndcdn.com/avatars-000001552142-pbw8yd-large.jpg?142a848", 84 | "country": "Germany", 85 | "full_name": "Johannes Wagener", 86 | "city": "Berlin" 87 | } 88 | ``` 89 | 90 | The `oauth2_json_user_id_path`, `oauth2_json_username_path`, `oauth2_json_name_path` and 91 | `oauth2_json_email_path` variables should be set to point to the appropriate attributes 92 | in the JSON. 93 | 94 | The only mandatory attribute is _id_ - we need that so when the user logs on in the future 95 | that we can pull up the correct account. The others are great if available -- they will 96 | make the signup process faster for the user as they will be pre-populated in the form. 97 | 98 | Here's how I configured the JSON path settings: 99 | 100 | ``` 101 | oauth2_json_user_id_path: 'id' 102 | oauth2_json_username_path: 'permalink' 103 | oauth2_json_name_path: 'full_name' 104 | ``` 105 | 106 | I used `permalink` because it seems more similar to what Discourse expects for a username 107 | than the username in their JSON. Notice I omitted the email path: SoundCloud do not 108 | provide an email so the user will have to provide and verify this when they sign up 109 | the first time on Discourse. 110 | 111 | If the properties you want from your JSON object are nested, you can use periods. 112 | So for example if the API returned a different structure like this: 113 | 114 | ```json 115 | { 116 | "user": { 117 | "id": 1234, 118 | "email": { 119 | "address": "test@example.com" 120 | } 121 | } 122 | } 123 | ``` 124 | 125 | You could use `user.id` for the `oauth2_json_user_id_path` and `user.email.address` for `oauth2_json_email_path`. 126 | 127 | ## Part 3: Test it with Google OAuth 2.0 Server 128 | 129 | To test this plugin in your local dev environment you can use Google OAuth 2.0 Server. Follow [this guide](https://support.google.com/cloud/answer/6158849?hl=en) to create new OAuth client id & secret. 130 | 131 | - While creating it choose "Web application" as "Application type". 132 | - Add `http://localhost:3000` in "Authorized JavaScript origins" and `http://localhost:3000/auth/oauth2_basic/callback` in "Authorized redirect URIs" fields. 133 | - Then add following site settings in your admin panel. 134 | 135 | ```json 136 | { 137 | "oauth2_enabled": true, 138 | "oauth2_client_id": "YOUR_PROJECT_CLIENT_ID", 139 | "oauth2_client_secret": "YOUR_PROJECT_CLIENT_SECRET", 140 | "oauth2_authorize_url": "https://accounts.google.com/o/oauth2/auth", 141 | "oauth2_token_url": "https://www.googleapis.com/oauth2/v3/token", 142 | "oauth2_user_json_url": "https://www.googleapis.com/userinfo/v2/me", 143 | "oauth2_json_user_id_path": "id", 144 | "oauth2_json_user_name_path": "name", 145 | "oauth2_json_user_email_path": "email", 146 | "oauth2_json_user_avatar_path": "picture", 147 | "oauth2_email_verified": true, 148 | "oauth2_scope": "https://www.googleapis.com/auth/userinfo.email" 149 | } 150 | ``` 151 | 152 | That's it! You can check it now in your browser. 153 | 154 | Good luck setting up custom OAuth2 on your Discourse! 155 | 156 | ### Issues 157 | 158 | Please use [this topic on meta](https://meta.discourse.org/t/oauth2-basic-support/33879) to discuss 159 | issues with the plugin, including bugs and feature requests. 160 | 161 | ### How to run tests 162 | 163 | Make sure the plugin has been installed, then from the discourse directory run: 164 | 165 | ``` 166 | LOAD_PLUGINS=1 bundle exec rspec plugins/discourse-oauth2-basic/spec/plugin_spec.rb 167 | ``` 168 | 169 | ### License 170 | 171 | MIT 172 | -------------------------------------------------------------------------------- /lib/oauth2_basic_authenticator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class OAuth2BasicAuthenticator < Auth::ManagedAuthenticator 4 | def name 5 | "oauth2_basic" 6 | end 7 | 8 | def can_revoke? 9 | SiteSetting.oauth2_allow_association_change 10 | end 11 | 12 | def can_connect_existing_user? 13 | SiteSetting.oauth2_allow_association_change 14 | end 15 | 16 | def register_middleware(omniauth) 17 | omniauth.provider :oauth2_basic, 18 | name: name, 19 | setup: 20 | lambda { |env| 21 | opts = env["omniauth.strategy"].options 22 | opts[:client_id] = SiteSetting.oauth2_client_id 23 | opts[:client_secret] = SiteSetting.oauth2_client_secret 24 | opts[:provider_ignores_state] = SiteSetting.oauth2_disable_csrf 25 | opts[:client_options] = { 26 | authorize_url: SiteSetting.oauth2_authorize_url, 27 | token_url: SiteSetting.oauth2_token_url, 28 | token_method: SiteSetting.oauth2_token_url_method.downcase.to_sym, 29 | } 30 | opts[:authorize_options] = SiteSetting 31 | .oauth2_authorize_options 32 | .split("|") 33 | .map(&:to_sym) 34 | 35 | if SiteSetting.oauth2_authorize_signup_url.present? && 36 | ActionDispatch::Request.new(env).params["signup"].present? 37 | opts[:client_options][ 38 | :authorize_url 39 | ] = SiteSetting.oauth2_authorize_signup_url 40 | end 41 | 42 | if SiteSetting.oauth2_send_auth_header? && 43 | SiteSetting.oauth2_send_auth_body? 44 | # For maximum compatibility we include both header and body auth by default 45 | # This is a little unusual, and utilising multiple authentication methods 46 | # is technically disallowed by the spec (RFC2749 Section 5.2) 47 | opts[:client_options][:auth_scheme] = :request_body 48 | opts[:token_params] = { 49 | headers: { 50 | "Authorization" => basic_auth_header, 51 | }, 52 | } 53 | elsif SiteSetting.oauth2_send_auth_header? 54 | opts[:client_options][:auth_scheme] = :basic_auth 55 | else 56 | opts[:client_options][:auth_scheme] = :request_body 57 | end 58 | 59 | if SiteSetting.oauth2_scope.present? 60 | opts[:scope] = SiteSetting.oauth2_scope 61 | end 62 | 63 | opts[:client_options][:connection_build] = lambda do |builder| 64 | if SiteSetting.oauth2_debug_auth && defined?(OAuth2FaradayFormatter) 65 | builder.response :logger, 66 | Rails.logger, 67 | { bodies: true, formatter: OAuth2FaradayFormatter } 68 | end 69 | 70 | builder.request :url_encoded # form-encode POST params 71 | builder.adapter FinalDestination::FaradayAdapter # make requests with FinalDestination::HTTP 72 | end 73 | } 74 | end 75 | 76 | def basic_auth_header 77 | "Basic " + 78 | Base64.strict_encode64("#{SiteSetting.oauth2_client_id}:#{SiteSetting.oauth2_client_secret}") 79 | end 80 | 81 | def walk_path(fragment, segments, seg_index = 0) 82 | first_seg = segments[seg_index] 83 | return if first_seg.blank? || fragment.blank? 84 | return nil unless fragment.is_a?(Hash) || fragment.is_a?(Array) 85 | first_seg = segments[seg_index].scan(/([\d+])/).length > 0 ? first_seg.split("[")[0] : first_seg 86 | if fragment.is_a?(Hash) 87 | deref = fragment[first_seg] 88 | else 89 | array_index = 0 90 | if (seg_index > 0) 91 | last_index = segments[seg_index - 1].scan(/([\d+])/).flatten() || [0] 92 | array_index = last_index.length > 0 ? last_index[0].to_i : 0 93 | end 94 | if fragment.any? && fragment.length >= array_index - 1 95 | deref = fragment[array_index][first_seg] 96 | else 97 | deref = nil 98 | end 99 | end 100 | 101 | if deref.blank? || seg_index == segments.size - 1 102 | deref 103 | else 104 | seg_index += 1 105 | walk_path(deref, segments, seg_index) 106 | end 107 | end 108 | 109 | def json_walk(result, user_json, prop, custom_path: nil) 110 | path = custom_path || SiteSetting.public_send("oauth2_json_#{prop}_path") 111 | if path.present? 112 | #this.[].that is the same as this.that, allows for both this[0].that and this.[0].that path styles 113 | path = path.gsub(".[].", ".").gsub(".[", "[") 114 | segments = parse_segments(path) 115 | val = walk_path(user_json, segments) 116 | # [] should be nil, false should be false 117 | result[prop] = val.presence || (val == [] ? nil : val) 118 | end 119 | end 120 | 121 | def parse_segments(path) 122 | segments = [+""] 123 | quoted = false 124 | escaped = false 125 | 126 | path 127 | .split("") 128 | .each do |char| 129 | next_char_escaped = false 130 | if !escaped && (char == '"') 131 | quoted = !quoted 132 | elsif !escaped && !quoted && (char == ".") 133 | segments.append +"" 134 | elsif !escaped && (char == '\\') 135 | next_char_escaped = true 136 | else 137 | segments.last << char 138 | end 139 | escaped = next_char_escaped 140 | end 141 | 142 | segments 143 | end 144 | 145 | def log(info) 146 | Rails.logger.warn("OAuth2 Debugging: #{info}") if SiteSetting.oauth2_debug_auth 147 | end 148 | 149 | def fetch_user_details(token, id) 150 | user_json_url = SiteSetting.oauth2_user_json_url.sub(":token", token.to_s).sub(":id", id.to_s) 151 | user_json_method = SiteSetting.oauth2_user_json_url_method.downcase.to_sym 152 | 153 | bearer_token = "Bearer #{token}" 154 | connection = Faraday.new { |f| f.adapter FinalDestination::FaradayAdapter } 155 | headers = { "Authorization" => bearer_token, "Accept" => "application/json" } 156 | user_json_response = connection.run_request(user_json_method, user_json_url, nil, headers) 157 | 158 | log <<-LOG 159 | user_json request: #{user_json_method} #{user_json_url} 160 | 161 | request headers: #{headers} 162 | 163 | response status: #{user_json_response.status} 164 | 165 | response body: 166 | #{user_json_response.body} 167 | LOG 168 | 169 | if user_json_response.status == 200 170 | user_json = JSON.parse(user_json_response.body) 171 | 172 | log("user_json:\n#{user_json.to_yaml}") 173 | 174 | result = {} 175 | if user_json.present? 176 | json_walk(result, user_json, :user_id) 177 | json_walk(result, user_json, :username) 178 | json_walk(result, user_json, :name) 179 | json_walk(result, user_json, :email) 180 | json_walk(result, user_json, :email_verified) 181 | json_walk(result, user_json, :avatar) 182 | 183 | DiscoursePluginRegistry.oauth2_basic_additional_json_paths.each do |detail| 184 | prop = "extra:#{detail}" 185 | json_walk(result, user_json, prop, custom_path: detail) 186 | end 187 | end 188 | result 189 | else 190 | nil 191 | end 192 | end 193 | 194 | def primary_email_verified?(auth) 195 | return true if SiteSetting.oauth2_email_verified 196 | verified = auth["info"]["email_verified"] 197 | verified = true if verified == "true" 198 | verified = false if verified == "false" 199 | verified 200 | end 201 | 202 | def always_update_user_email? 203 | SiteSetting.oauth2_overrides_email 204 | end 205 | 206 | def after_authenticate(auth, existing_account: nil) 207 | log <<-LOG 208 | after_authenticate response: 209 | 210 | creds: 211 | #{auth["credentials"].to_hash.to_yaml} 212 | 213 | uid: #{auth["uid"]} 214 | 215 | info: 216 | #{auth["info"].to_hash.to_yaml} 217 | 218 | extra: 219 | #{auth["extra"].to_hash.to_yaml} 220 | LOG 221 | 222 | if SiteSetting.oauth2_fetch_user_details? && SiteSetting.oauth2_user_json_url.present? 223 | if fetched_user_details = fetch_user_details(auth["credentials"]["token"], auth["uid"]) 224 | auth["uid"] = fetched_user_details[:user_id] if fetched_user_details[:user_id] 225 | auth["info"]["nickname"] = fetched_user_details[:username] if fetched_user_details[ 226 | :username 227 | ] 228 | auth["info"]["image"] = fetched_user_details[:avatar] if fetched_user_details[:avatar] 229 | %w[name email email_verified].each do |property| 230 | auth["info"][property] = fetched_user_details[property.to_sym] if fetched_user_details[ 231 | property.to_sym 232 | ] 233 | end 234 | 235 | DiscoursePluginRegistry.oauth2_basic_additional_json_paths.each do |detail| 236 | auth["extra"][detail] = fetched_user_details["extra:#{detail}"] 237 | end 238 | 239 | DiscoursePluginRegistry.oauth2_basic_required_json_paths.each do |x| 240 | if fetched_user_details[x[:path]] != x[:required_value] 241 | result = Auth::Result.new 242 | result.failed = true 243 | result.failed_reason = x[:error_message] 244 | return result 245 | end 246 | end 247 | else 248 | result = Auth::Result.new 249 | result.failed = true 250 | result.failed_reason = I18n.t("login.authenticator_error_fetch_user_details") 251 | return result 252 | end 253 | end 254 | 255 | super(auth, existing_account: existing_account) 256 | end 257 | 258 | def enabled? 259 | SiteSetting.oauth2_enabled 260 | end 261 | end 262 | -------------------------------------------------------------------------------- /spec/plugin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe OAuth2BasicAuthenticator do 6 | describe "after_authenticate" do 7 | before { SiteSetting.oauth2_user_json_url = "https://provider.com/user" } 8 | 9 | let(:user) { Fabricate(:user) } 10 | let(:authenticator) { OAuth2BasicAuthenticator.new } 11 | 12 | let(:auth) do 13 | OmniAuth::AuthHash.new( 14 | "provider" => "oauth2_basic", 15 | "credentials" => { 16 | token: "token", 17 | }, 18 | "uid" => "123456789", 19 | "info" => { 20 | id: "id", 21 | }, 22 | "extra" => { 23 | }, 24 | ) 25 | end 26 | 27 | before(:each) { SiteSetting.oauth2_email_verified = true } 28 | 29 | it "finds user by email" do 30 | authenticator.expects(:fetch_user_details).returns(email: user.email) 31 | result = authenticator.after_authenticate(auth) 32 | expect(result.user).to eq(user) 33 | end 34 | 35 | it "validates user email if provider has verified" do 36 | SiteSetting.oauth2_email_verified = false 37 | authenticator.stubs(:fetch_user_details).returns(email: user.email, email_verified: true) 38 | result = authenticator.after_authenticate(auth) 39 | expect(result.email_valid).to eq(true) 40 | end 41 | 42 | it "doesn't validate user email if provider hasn't verified" do 43 | SiteSetting.oauth2_email_verified = false 44 | authenticator.stubs(:fetch_user_details).returns(email: user.email, email_verified: nil) 45 | result = authenticator.after_authenticate(auth) 46 | expect(result.email_valid).to eq(false) 47 | end 48 | 49 | it "doesn't affect the site setting" do 50 | SiteSetting.oauth2_email_verified = true 51 | authenticator.stubs(:fetch_user_details).returns(email: user.email, email_verified: false) 52 | result = authenticator.after_authenticate(auth) 53 | expect(result.email_valid).to eq(true) 54 | end 55 | 56 | it "handles true/false strings from identity provider" do 57 | SiteSetting.oauth2_email_verified = false 58 | authenticator.stubs(:fetch_user_details).returns(email: user.email, email_verified: "true") 59 | result = authenticator.after_authenticate(auth) 60 | expect(result.email_valid).to eq(true) 61 | 62 | authenticator.stubs(:fetch_user_details).returns(email: user.email, email_verified: "false") 63 | result = authenticator.after_authenticate(auth) 64 | expect(result.email_valid).to eq(false) 65 | end 66 | 67 | describe "fetch_user_details" do 68 | before(:each) do 69 | SiteSetting.oauth2_fetch_user_details = true 70 | SiteSetting.oauth2_user_json_url = "https://provider.com/user" 71 | SiteSetting.oauth2_user_json_url_method = "GET" 72 | SiteSetting.oauth2_json_email_path = "account.email" 73 | end 74 | 75 | let(:success_response) do 76 | { status: 200, body: '{"account":{"email":"newemail@example.com"}}' } 77 | end 78 | 79 | let(:fail_response) { { status: 403 } } 80 | 81 | it "works" do 82 | stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(success_response) 83 | result = authenticator.after_authenticate(auth) 84 | expect(result.email).to eq("newemail@example.com") 85 | 86 | SiteSetting.oauth2_user_json_url_method = "POST" 87 | stub_request(:post, SiteSetting.oauth2_user_json_url).to_return(success_response) 88 | result = authenticator.after_authenticate(auth) 89 | expect(result.email).to eq("newemail@example.com") 90 | end 91 | 92 | it "returns an standardised result if the http request fails" do 93 | stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(fail_response) 94 | result = authenticator.after_authenticate(auth) 95 | expect(result.failed).to eq(true) 96 | 97 | SiteSetting.oauth2_user_json_url_method = "POST" 98 | stub_request(:post, SiteSetting.oauth2_user_json_url).to_return(fail_response) 99 | result = authenticator.after_authenticate(auth) 100 | expect(result.failed).to eq(true) 101 | end 102 | 103 | describe "fetch custom attributes" do 104 | after { DiscoursePluginRegistry.reset_register!(:oauth2_basic_additional_json_paths) } 105 | 106 | let(:response) do 107 | { 108 | status: 200, 109 | body: '{"account":{"email":"newemail@example.com","custom_attr":"received"}}', 110 | } 111 | end 112 | 113 | it "stores custom attributes in the user associated account" do 114 | custom_path = "account.custom_attr" 115 | DiscoursePluginRegistry.register_oauth2_basic_additional_json_path( 116 | custom_path, 117 | Plugin::Instance.new, 118 | ) 119 | stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(response) 120 | 121 | result = authenticator.after_authenticate(auth) 122 | associated_account = UserAssociatedAccount.last 123 | 124 | expect(associated_account.extra[custom_path]).to eq("received") 125 | end 126 | end 127 | 128 | describe "required attributes" do 129 | after { DiscoursePluginRegistry.reset_register!(:oauth2_basic_required_json_paths) } 130 | 131 | it "'authenticates' successfully if required json path is fulfilled" do 132 | DiscoursePluginRegistry.register_oauth2_basic_additional_json_path( 133 | "account.is_legit", 134 | Plugin::Instance.new, 135 | ) 136 | DiscoursePluginRegistry.register_oauth2_basic_required_json_path( 137 | { path: "extra:account.is_legit", required_value: true }, 138 | Plugin::Instance.new, 139 | ) 140 | 141 | response = { 142 | status: 200, 143 | body: '{"account":{"email":"newemail@example.com","is_legit":true}}', 144 | } 145 | stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(response) 146 | 147 | result = authenticator.after_authenticate(auth) 148 | expect(result.failed).to eq(false) 149 | end 150 | 151 | it "fails 'authentication' if required json path is unfulfilled" do 152 | DiscoursePluginRegistry.register_oauth2_basic_additional_json_path( 153 | "account.is_legit", 154 | Plugin::Instance.new, 155 | ) 156 | DiscoursePluginRegistry.register_oauth2_basic_required_json_path( 157 | { 158 | path: "extra:account.is_legit", 159 | required_value: true, 160 | error_message: "You're not legit", 161 | }, 162 | Plugin::Instance.new, 163 | ) 164 | response = { 165 | status: 200, 166 | body: '{"account":{"email":"newemail@example.com","is_legit":false}}', 167 | } 168 | stub_request(:get, SiteSetting.oauth2_user_json_url).to_return(response) 169 | 170 | result = authenticator.after_authenticate(auth) 171 | expect(result.failed).to eq(true) 172 | expect(result.failed_reason).to eq("You're not legit") 173 | end 174 | end 175 | end 176 | 177 | describe "avatar downloading" do 178 | before do 179 | Jobs.run_later! 180 | SiteSetting.oauth2_fetch_user_details = true 181 | SiteSetting.oauth2_email_verified = true 182 | end 183 | 184 | let(:job_klass) { Jobs::DownloadAvatarFromUrl } 185 | 186 | before do 187 | png = 188 | Base64.decode64( 189 | "R0lGODlhAQABALMAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwICAgP8AAAD/AP//AAAA//8A/wD//wBiZCH5BAEAAA8ALAAAAAABAAEAAAQC8EUAOw==", 190 | ) 191 | stub_request(:get, "http://avatar.example.com/avatar.png").to_return( 192 | body: png, 193 | headers: { 194 | "Content-Type" => "image/png", 195 | }, 196 | ) 197 | end 198 | 199 | it "enqueues a download_avatar_from_url job for existing user" do 200 | authenticator.expects(:fetch_user_details).returns( 201 | email: user.email, 202 | avatar: "http://avatar.example.com/avatar.png", 203 | ) 204 | expect { authenticator.after_authenticate(auth) }.to change { job_klass.jobs.count }.by(1) 205 | 206 | job_args = job_klass.jobs.last["args"].first 207 | 208 | expect(job_args["url"]).to eq("http://avatar.example.com/avatar.png") 209 | expect(job_args["user_id"]).to eq(user.id) 210 | expect(job_args["override_gravatar"]).to eq(false) 211 | end 212 | 213 | it "enqueues a download_avatar_from_url job for new user" do 214 | authenticator.expects(:fetch_user_details).returns( 215 | email: "unknown@user.com", 216 | avatar: "http://avatar.example.com/avatar.png", 217 | ) 218 | 219 | auth_result = nil 220 | expect { auth_result = authenticator.after_authenticate(auth) }.not_to change { 221 | job_klass.jobs.count 222 | } 223 | 224 | expect { authenticator.after_create_account(user, auth_result) }.to change { 225 | job_klass.jobs.count 226 | }.by(1) 227 | 228 | job_args = job_klass.jobs.last["args"].first 229 | 230 | expect(job_args["url"]).to eq("http://avatar.example.com/avatar.png") 231 | expect(job_args["user_id"]).to eq(user.id) 232 | expect(job_args["override_gravatar"]).to eq(false) 233 | end 234 | end 235 | end 236 | 237 | it "can walk json" do 238 | authenticator = OAuth2BasicAuthenticator.new 239 | json_string = '{"user":{"id":1234,"email":{"address":"test@example.com"}}}' 240 | SiteSetting.oauth2_json_email_path = "user.email.address" 241 | result = authenticator.json_walk({}, JSON.parse(json_string), :email) 242 | 243 | expect(result).to eq "test@example.com" 244 | end 245 | 246 | it "allows keys containing dots, if wrapped in quotes" do 247 | authenticator = OAuth2BasicAuthenticator.new 248 | json_string = '{"www.example.com/uid": "myuid"}' 249 | SiteSetting.oauth2_json_user_id_path = '"www.example.com/uid"' 250 | result = authenticator.json_walk({}, JSON.parse(json_string), :user_id) 251 | 252 | expect(result).to eq "myuid" 253 | end 254 | 255 | it "allows keys containing dots, if escaped" do 256 | authenticator = OAuth2BasicAuthenticator.new 257 | json_string = '{"www.example.com/uid": "myuid"}' 258 | SiteSetting.oauth2_json_user_id_path = 'www\.example\.com/uid' 259 | result = authenticator.json_walk({}, JSON.parse(json_string), :user_id) 260 | 261 | expect(result).to eq "myuid" 262 | end 263 | 264 | it "allows keys containing literal backslashes, if escaped" do 265 | authenticator = OAuth2BasicAuthenticator.new 266 | # This 'single quoted heredoc' syntax means we don't have to escape backslashes in Ruby 267 | # What you see is exactly what the user would enter in the site settings 268 | json_string = <<~'_'.chomp 269 | {"www.example.com/uid\\": "myuid"} 270 | _ 271 | SiteSetting.oauth2_json_user_id_path = <<~'_'.chomp 272 | www\.example\.com/uid\\ 273 | _ 274 | result = authenticator.json_walk({}, JSON.parse(json_string), :user_id) 275 | expect(result).to eq "myuid" 276 | end 277 | 278 | it "can walk json that contains an array" do 279 | authenticator = OAuth2BasicAuthenticator.new 280 | json_string = 281 | '{"email":"test@example.com","identities":[{"user_id":"123456789","provider":"auth0","isSocial":false}]}' 282 | SiteSetting.oauth2_json_user_id_path = "identities.[].user_id" 283 | result = authenticator.json_walk({}, JSON.parse(json_string), :user_id) 284 | 285 | expect(result).to eq "123456789" 286 | end 287 | 288 | it "can walk json and handle an empty array" do 289 | authenticator = OAuth2BasicAuthenticator.new 290 | json_string = '{"email":"test@example.com","identities":[]}' 291 | SiteSetting.oauth2_json_user_id_path = "identities.[].user_id" 292 | result = authenticator.json_walk({}, JSON.parse(json_string), :user_id) 293 | 294 | expect(result).to eq nil 295 | end 296 | 297 | it "can walk json and find values by index in an array" do 298 | authenticator = OAuth2BasicAuthenticator.new 299 | json_string = '{"emails":[{"value":"test@example.com"},{"value":"test2@example.com"}]}' 300 | SiteSetting.oauth2_json_email_path = "emails[1].value" 301 | result = authenticator.json_walk({}, JSON.parse(json_string), :email) 302 | 303 | expect(result).to eq "test2@example.com" 304 | end 305 | 306 | it "can walk json and download avatar" do 307 | authenticator = OAuth2BasicAuthenticator.new 308 | json_string = '{"user":{"avatar":"http://example.com/1.png"}}' 309 | SiteSetting.oauth2_json_avatar_path = "user.avatar" 310 | result = authenticator.json_walk({}, JSON.parse(json_string), :avatar) 311 | 312 | expect(result).to eq "http://example.com/1.png" 313 | end 314 | 315 | it "can walk json and appropriately assign a `false`" do 316 | authenticator = OAuth2BasicAuthenticator.new 317 | json_string = '{"user":{"id":1234, "data": {"address":"test@example.com", "is_cat": false}}}' 318 | SiteSetting.oauth2_json_email_verified_path = "user.data.is_cat" 319 | result = 320 | authenticator.json_walk( 321 | {}, 322 | JSON.parse(json_string), 323 | "extra:user.data.is_cat", 324 | custom_path: "user.data.is_cat", 325 | ) 326 | 327 | expect(result).to eq false 328 | end 329 | 330 | describe "token_callback" do 331 | let(:user) { Fabricate(:user) } 332 | let(:strategy) { OmniAuth::Strategies::Oauth2Basic.new({}) } 333 | let(:authenticator) { OAuth2BasicAuthenticator.new } 334 | 335 | let(:auth) do 336 | OmniAuth::AuthHash.new( 337 | "provider" => "oauth2_basic", 338 | "credentials" => { 339 | "token" => "token", 340 | }, 341 | "uid" => "e028b1b918853eca7fba208a9d7e9d29a6e93c57", 342 | "info" => { 343 | "name" => "Sammy the Shark", 344 | "email" => "sammy@digitalocean.com", 345 | }, 346 | "extra" => { 347 | }, 348 | ) 349 | end 350 | 351 | let(:access_token) do 352 | { 353 | "params" => { 354 | "info" => { 355 | "name" => "Sammy the Shark", 356 | "email" => "sammy@digitalocean.com", 357 | "uuid" => "e028b1b918853eca7fba208a9d7e9d29a6e93c57", 358 | }, 359 | }, 360 | } 361 | end 362 | 363 | before(:each) do 364 | SiteSetting.oauth2_callback_user_id_path = "params.info.uuid" 365 | SiteSetting.oauth2_callback_user_info_paths = "name:params.info.name|email:params.info.email" 366 | end 367 | 368 | it "can retrieve user id from access token callback" do 369 | strategy.stubs(:access_token).returns(access_token) 370 | expect(strategy.uid).to eq "e028b1b918853eca7fba208a9d7e9d29a6e93c57" 371 | end 372 | 373 | it "can retrieve user properties from access token callback" do 374 | strategy.stubs(:access_token).returns(access_token) 375 | expect(strategy.info["name"]).to eq "Sammy the Shark" 376 | expect(strategy.info["email"]).to eq "sammy@digitalocean.com" 377 | end 378 | 379 | it "does apply user properties from access token callback in after_authenticate" do 380 | SiteSetting.oauth2_fetch_user_details = true 381 | authenticator.stubs(:fetch_user_details).returns(email: "sammy@digitalocean.com") 382 | result = authenticator.after_authenticate(auth) 383 | 384 | expect(result.extra_data[:uid]).to eq "e028b1b918853eca7fba208a9d7e9d29a6e93c57" 385 | expect(result.name).to eq "Sammy the Shark" 386 | expect(result.email).to eq "sammy@digitalocean.com" 387 | end 388 | 389 | it "does work if user details are not fetched" do 390 | SiteSetting.oauth2_fetch_user_details = false 391 | result = authenticator.after_authenticate(auth) 392 | 393 | expect(result.extra_data[:uid]).to eq "e028b1b918853eca7fba208a9d7e9d29a6e93c57" 394 | expect(result.name).to eq "Sammy the Shark" 395 | expect(result.email).to eq "sammy@digitalocean.com" 396 | end 397 | end 398 | end 399 | --------------------------------------------------------------------------------