export default {"/search": {"posts":[{"id":61693,"name":"Manoel Lemos","username":"mlemos","avatar_template":"/letter_avatar/mlemos/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-07-15T21:53:56.337-04:00","cooked":"
Gents, I'm using an very interesting tool to drive traffic across the different destinations of my community. One destination is the discussion forum running Discourse and other is the blog running WordPress.
\n\nThis tool is called Hello Bar and it is basically a bar that stays in the top of the site and links to other places or can be used to collect emails or social networks followers. It worked fine when I added the bar to my Wordpress Blog, but it failed (a bit) when added to my Discourse forum.
\n\nYou can check the two situations here:
\n\nThe error is that the Discourse page was suposed to be pushed down by the Hello Bar, but it isn't being fully pushed down. Then the layout is broken.
\n\nCan anyone help me with this?
","post_number":1,"post_type":1,"updated_at":"2014-07-15T21:53:56.337-04:00","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":30,"incoming_link_count":2,"reads":40,"score":19.5,"yours":false,"topic_slug":null,"topic_id":17638,"display_username":"Manoel Lemos","primary_group_name":null,"version":2,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":null,"actions_summary":[{"id":2,"count":0,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":false,"admin":false,"staff":false,"user_id":7595,"hidden":false,"hidden_reason_id":null,"trust_level":1,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"blurb":"...the discussion forum running Discourse and other is the blog running WordPress. This tool is called Hello Bar and it is basically a bar that stays in the top of the site and links to other places or can be..."},{"id":56514,"name":"Ova Light","username":"ChrisOva","avatar_template":"/letter_avatar/chrisova/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-06-13T02:56:00.794-04:00","cooked":"Do you know what are the elements whichI need to modify in the custom CSS editor in order for these parts of the forum to change color ?
\n\n\n\nIs anyone here willing to work for a theme? (50$)
\n\nThanks for reading !
","post_number":1,"post_type":1,"updated_at":"2014-06-13T03:05:31.865-04:00","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":24,"incoming_link_count":1,"reads":31,"score":57.4,"yours":false,"topic_slug":null,"topic_id":16504,"display_username":"Ova Light","primary_group_name":null,"version":5,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":null,"actions_summary":[{"id":2,"count":1,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":false,"admin":false,"staff":false,"user_id":10477,"hidden":false,"hidden_reason_id":null,"trust_level":2,"deleted_at":null,"user_deleted":false,"edit_reason":"downloaded local copies of images","can_view_edit_history":true,"wiki":false,"blurb":"Do you know what are the elements whichI need to modify in the custom CSS editor in order for these parts of the forum to change color ? 00000674.png 00000674.png 2644x932 239 KB Is anyone here wil..."},{"id":40862,"name":"Moe","username":"Moe","avatar_template":"/letter_avatar/moe/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-02-14T18:35:48.395-05:00","cooked":"Hello,
\n\nFirst and foremost, thanks to the developers of Discourse and everyone who is making great efforts in creating an awesome forum!
\n\nI am a Discouse newbie and I am trying to do sso using the CAS sso auth plugin in https://github.com/eriko/cas_sso .
\n\nI am currently making some experiments in authenticating users in Discourse using a test web app I am using as CAS server. I have set up discourse in a VM (vagrant) whereas the CAS server runs in the host machine. I have installed the sso plugin and set the values as indicated (i.e. cas_sso_host, cas_sso_port, etc, as it is a non-standard CAS server), with ssh disabled.
\n\nOne thing that I noticed is that it seems that there seems to be a cross domain protection acting, the following is a message that appears in the console when I go to login in vagrant discourse:
Started GET \"/session/csrf\" for 10.0.2.2 at 2014-02-14 17:53:12 -0500\nProcessing by SessionController#csrf as */*\nCompleted 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms)
\n\nHere 10.0.2.2 is the ip of the CAS server. This server is accessible from vagrant, I tested access to the CAS server URLs using lynx (everything works fine). I should likely mention also that cas_sso_login_url is set to /login and cas_sso_path is set to /cas in the Discourse sso plugin options. I have been also monitoring requests to /cas/login in the CAS server and none of my login attempts from Discourse have made it there.
\n\nI am brand new to Discourse and Ruby, so I am having a bit of a struggle here and any insight would be greatly appreciated.
\n\nThank you very much in advance for your time and excellent disposition.
\n\nBest regards,
Moe
For the feature I was working on yesterday, @codinghorror wanted a rather complex sentence.
\n\nThere is 1 unread and 9 new topics remaining, or browse other topics in [category]\n\n
This seemingly simple sentence was a royal nightmare to localize with our existing localization system. Think through all the permutations:
\n\n\"There are 2 unread and 9 new topics remaining, or browse other topics in [category]\"
\"There are 2 unread and 1 new topic remaining, or browse other topics in [category]\"
\"There is 1 unread and 1 new topic remaining, or browse other topics in [category]\"
Trouble with our current system was that you have no sane way of building these kind of sentences, see: http://stackoverflow.com/questions/16825932/clean-pattern-for-localizing-sentences-in-rails-i18n , you can only easily localize one count in a non compound sentence.
\n\nTo alleviate this I introduce a new mechanism that is available (optionally) client side. The above sentence is localized using:
\n\nThere {UNREAD, plural, \n one {is <a href='/unread'>1 unread</a>} \n other {are <a href='/unread'># unread</a>}\n} and {NEW, plural, \n one {<a href='/new'>1 new</a> topic} \n other {<a href='/new'># new</a> topics}} remaining, or browse other topics in {catLink}
\n\nThe client localization file has a special rule, if a key ends with _MF it is interpreted as a MessageFormat message, then to access it on the client you use:
\n\nI18n.messageFormat(\"topic.read_more_in_category_MF\", {\"UNREAD\": unreadTopics, \"NEW\": newTopics, catLink: opts.catLink})
\n\nYou can see a few other examples here:
\n\n\n\nWe do not plan at the moment to move to message format style localization everywhere, however it is nice to have this extra bit of flexibility that lets us generate interesting sentences.
\n\nOn a technical note, this feature adds almost no weight to the client side JavaScript, all message format strings are pre-compiled into a JavaScript function with no external dependencies. The tricks used can be viewed here: https://github.com/discourse/discourse/blob/master/lib/js_locale_helper.rb
\n\nf = \"hello\"\nf() => \"hello\"\n\nf = \"hello {WORLD}\"\nf(WORLD: \"world\") => \"hello world\" \nf(WORLD: \"other world\") => \"hello other world\" \n\nf = \"I have {HATS, plural, one {one hat} other {# hats}}\"\nf(HATS: 1) => \"I have one hat\"\nf(HATS: 10) => \"I have 10 hats\" \n\nf = \"I am a {GENDER, select, male {boy}, female {girl}}\"\nf(GENDER: \"male\") => \"I am a boy\"\nf(GENDER: \"female\") => \"I am a girl\"
\n\nOur plan for now is to use this strategically, however it is worth noting that this gives more flexibility in localization, for example in czech, the plural form is rather interesting as @kuba could attest :
\n\nMessageFormat.locale.cs = function (n) {\n if (n == 1) {\n return 'one';\n }\n if (n == 2 || n == 3 || n == 4) {\n return 'few';\n }\n return 'other';\n};
\n\nMessage Format supports this fine, built in.
\n\nf = \"I have {HATS, plural, one {one hat} other {# hats} few {# few hats}}\"
","post_number":1,"post_type":1,"updated_at":"2013-05-30T21:31:57.135-04:00","reply_count":1,"reply_to_post_number":null,"quote_count":0,"avg_time":33,"incoming_link_count":44,"reads":68,"score":450.25,"yours":false,"topic_slug":null,"topic_id":7035,"display_username":"Sam Saffron","primary_group_name":"discourse","version":3,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":"co-founder","actions_summary":[{"id":2,"count":6,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":true,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":3,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"blurb":"...hub.com/discourse/discourse/blob/master/lib/js_locale_helper.rb 1 minute Message Format primer f = \"hello\" f() = > \"hello\" f = \"hello {WORLD}\" f(WORLD: \"world\") = > \"hello world\" f(WORLD: \"other world\") =..."},{"id":41969,"name":"Sam Saffron","username":"sam","avatar_template":"/letter_avatar/sam/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-02-25T03:30:34.423-05:00","cooked":"Discourse now ships with official hooks to perform auth offsite.
\n\nMany sites wish to integrate with a Discourse site, however want to keep all user registration in a separate site. In such a setup all Login operations should be outsourced to a different site.
\n\nThe intention around SSO is to replace Discourse authentication, if you would like to add a new provider see existing plugins such as: https://meta.discourse.org/t/vk-com-login-vkontakte/12987
\n\nTo enable single sign on you have 3 settings you need to fill out:
\n\n \n\nenable_sso
: must be enabled, global switchsso_url
: the offsite URL users will be sent to when attempting to log onsso_secret
: a secret string used to hash SSO payloads. Ensures payloads are authentic.
Once enable_sso
is set to true:
/session/sso
which in turn will redirect users to sso_url
with a signed payload.If you check enable_sso
by mistake and need to revert to the original state and no longer have access to the admin panel
run:
\n\n./launcher enter app\nrails c\nirb > SiteSetting.enable_sso = false\nirb > exit\nexit
\n\nDiscourse will redirect clients to sso_url
with a signed payload: (say sso_url is https://somesite.com/sso
)
You will receive incoming traffic with the following
\n\nhttps://somesite.com/sso?sso=PAYLOAD&sig=SIG
The payload is a Base64 encoded string comprising of a nonce. The payload is always a valid querystring.
\n\nFor example, if the nonce is ABCD. raw_payload will be:
\n\nnonce=ABCD
, this raw payload is base 64 encoded.
The endpoint being called must
\n\nhttp://discourse_site/session/sso_login?sso=payload&sig=sig
\nDiscourse will validate that the nonce is valid (if valid it will expire it right away so it can no longer be used) it will attempt to:
\n\nThe nonce (one time token) will expire automatically after 10 minutes. This means that as soon as the user is redirected to your site they have 10 minutes to log in / create a new account.
\n\nThe protocol is safe against replay attacks as nonce may only be used once.
\n\nDiscourse contains a reference implementation of the SSO class:
\n\n\n\n\nA trivial implementation would be:
\n\nclass DiscourseSsoController < ApplicationController\n def sso\n secret = \"MY_SECRET_STRING\"\n sso = SingleSignOn.parse(request.query_string, secret)\n sso.email = \"user@email.com\"\n sso.name = \"Bill Hicks\"\n sso.username = \"bill@hicks.com\"\n sso.external_id = \"123\" # unique to your application\n sso.sso_secret = secret\n\n redirect_to sso.to_url(\"http://l.discourse/session/sso_login\")\n end\nend
\n\nThe system always trusts emails provided by the single sign on endpoint. This means that if you had an existing account in the past on Discourse with SSO disabled, SSO will simply re-use it and avoid creating a new account.
\n\nIf you ever turn off SSO, users will be able to reset passwords and gain access back to their accounts.
\n\nGiven the following settings:
\n\nDiscourse domain: http://discuss.example.com
SSO url : http://www.example.com/discourse/sso
SSO secret: d836444a9e4084d5b224a60c208dce14
User attempt to login
\n\nNonce is generated: cb68251eefb5211e58c00ff1395f0c0b
Raw payload is generated: nonce=cb68251eefb5211e58c00ff1395f0c0b
Payload is Base64 encoded: bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=\\n
Payload is URL encoded: bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A
HMAC-SHA256 is generated on the encoded payload: 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
Finally browser is redirected to:
\n\nhttp://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A&sig=2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
On the other end
\n\nUser logs in:
\n\nname: sam\nexternal_id: hello123\nemail: test@test.com\nusername: samsam
\n\nnonce=cb68251eefb5211e58c00ff1395f0c0b&name=sam&username=samsam&email=test%40test.com&external_id=hello123
order does not matter, values are URL encoded
\n\n\"bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1z\\nYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRl\\ncm5hbF9pZD1oZWxsbzEyMw==\\n
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1z%0AYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRl%0Acm5hbF9pZD1oZWxsbzEyMw%3D%3D%0A
1c884222282f3feacd76802a9dd94e8bc8deba5d619b292bed75d63eb3152c0b
http://discuss.example.com/session/sso_login?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1z%0AYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRl%0Acm5hbF9pZD1oZWxsbzEyMw%3D%3D%0A&sig=1c884222282f3feacd76802a9dd94e8bc8deba5d619b292bed75d63eb3152c0b
We would like to gather more reference implementations for SSO on other platforms. If you have one please post to the Extensibility / SSO category.
Add session expiry and/or revalidation logic, so users are not logged in forever.
Create an API endpoint to log off users, in case somebody logs off the main site.
Consider adding a discourse_sso gem to make it easier to implement in Ruby.
2-Feb-2014
\n\n4-April-2014
\n\n24-April-2014
\n\n01-August-2014
\n\n