And specifically, they can post a topic, record an asciinema (terminal recording), capture the environment, and of course include text! Actually you can see a recording and full details in this pull request → https://github.com/vsoch/helpme/pull/33. So - what this comes down to is the user needing an api token to create a topic. They would export it once to their environment:
export HELPME_DISCOURSE_TOKEN=xxxxx
and then it would save to their personal configuration in $HOME. There is also an “admin” configuration that could provide a token to a user, but 1. it’s more likely the user has installed it on his/her own, and 2. The user could discover the token via looking into the running code. So ideally, I want:
Given I am a user of a discourse board, and user tokens are enabled, I have a web page I can go to and it will generate a token for me.
I can then plug it into the client to make a post!
The issue with using some “All Users” or admin token is that we can’t ship that with the software or even risk that it gets in the hands of anyone other than an admin. So the ideal is either already living with discourse, or on a separate server that has it too. Given the second, I’m not sure how we would connect the interface to a particular discourse board (and somewhat delegate the giving out of tokens) so I think the first is most logical. I’ve never made a plugin before, nor have I coded in ruby, so I would need much pointers on these things.
I see, I am open to a PR here that makes your use case somewhat easier:
helpme discourse somesite.com
You have no authentication token to somesite.com to create one visit:
http://somesite.com/api_key/new?application_name=helpme&public_key=ABCD&nonce=NONCE&client_id=client_id&auth_redirect...
Then user goes to web browser pastes in URL and at the end of the process INSTEAD of being redirected off site with the encrypted auth token we would simply render the encrypted token on screen.
It means this controller needs to accept another param:
Ah, fantastic! Let me start to look over the development docs and I’ll see what I can do. The example usage is spot on, even better than the old school “log in and generate” that I had in mind!
Do you have any tips/ examples/ templates that could help me? I have no idea what I’m doing, the most I can tell is that I might add @headless = params[:headless] but then I don’t actually know what that’s doing… I think I would want to:
add the parameter headless, with option to be empty (default) if not provided by the user (not headless mode)
based on the API key, use the API secret to encrypt it? (Where is that?)
heyo! My awesome collaborator is helping me out, so hopefully we can put our heads together and have a PR, maybe sometime over the weekend? I’ll ping you here if we run into trouble! His main language is Ruby, and he’s awesome, so I think for now we’re good! (and having fun too!)
---- edited!
hey @sam if we have a custom discourse repo, what is the quickest way to get a development server running? I’m looking at the docker-compose (and associated Docker images) from the main discourse image, and it’s quite a hairball. I don’t see any clear or easy way to combine the discourse base, the minidb, and minidb extras, and all the other dependencies that are stacked into there. What would you suggest?
hey @sam! This is fine if I just want to run the released discourse, but if I want to run a (development) version, from my Github repository, well I’ve been parsing through the dockerfiles this morning and it’s a nightmare - everything is a custom tool or command that has so many layers to reverse engineer I’m pulling my hair out. Ideally, we need an image (Dockerfile) that takes a discourse repository as an argument, and then generates the equivalent discourse:latest but with the custom respository. I can start with this docker-compose.yml
And I’d ideally just want to replace the name of the image with one that I’ve built. That’s all I’ve been done (for 4 hours now this morning) and I’m not making any progress because it’s so complicated. Is there no simple Dockerfile to do this? It might seem easy to you because you wrote all this / have developed it too for years, so the most I can do is tell you how challenging this is for (someone with pretty good container and development experience) to unravel. I’m very frustrated that this is so complicated. How can we do better?
As an example, when I develop some Django application, and let’s say the repository is downloaded to /code, I can just map a volume at $PWD:/code and then a restart to the container (via docker-compose) will update the app with my changes. Here in order to get to the source code addition I have to go all the way back to the base container:
And download the entire set of files that go into there, but then the container that uses it (discourse_dev) needs a whole set up of yaml configurations (also from the repository) h
which seem to be set up by various ruby scripts and there is no clear list of instructions for “how to deploy this with your own discourse.” If I try a different strategy to reproduce the discourse:latest (that has two base images of minideb and minideb-extras I again am hit with a custom install script from a packaged version, downloaded from a server that isn’t Github
You are saying this should be done by way of a plugin? And I can’t update the code there, and then test it locally? is there no logical way? As a developer, and given the discourse/discourse is the core codebase, I would suggest that there needs to be an avenue to do this.
And given yes to the above - how can the software stack be reproducible?
The only case that it makes sense to change the codebase rather than make changes in a plugin is if your change will be accepted in core. Otherwise, you’ll have to merge Discourse changes into your own, everyone who has done so was very sorry and spent lots of time and money undoing those changes.
Correct - that is my use case. I am testing code that will be a PR to core, and I’d like to have a development server to test before doing a PR. I could PR blindly but that is not something I have ever done, it seems like bad practice.
Please read the topic closely, that system is out there for hacking on you locally checked out source tree, strongly recommend not doing this docker compose bitnami hack
okay, I didn’t realize the bitnami code was a hack!
@sam I have a few more questions on the API call. How does the client_key fit in to this? Do you mean that helpme is registered as an application somewhere, and then given a key? And how is this distributed to the user?
I’m trying to map this to my understanding of OAuth2. With OAuth2 the provider would register the application (with a client id and secret) and the user doesn’t need to create a key. For example, to get a Github OAuth2 for Singularity Hub I:
register the application in Github
am given a client secret and key
add the secret and key to Singularity Hub
Singularity hub uses the key/secret to create tokens (token and refresh) on the user’s behalf
In our case, we are only dealing with one provider - discourse - and so there is no “Github” to register the application to. But maybe something like this?
register the helpme client on a discourse board (this is like the board giving approval for helpme to be used)
the discourse board turns on the endpoint to accept generation of tokens (and generated a client_key? where does it go / how is it used?)
the user goes through the authentication flow (accepting in browser) to get a token
the token is valid for some scope to post questions, etc.
I’m not sure where a public and private key fit in here, because it’s not typical to ask every user to do that, and actually would probably be too much and deter people from using it. The first validation is by way of the user accepting in the web interface, and the following come from the API token used after that. Could we talk about the generation and then use of the various keys/ secrets, and how you see this working?
An additional show action in the user_api_key controller shows the payload ( which the user will use to copy-paste into an environment variable)
Sounds like there’s a complication with the requirement for an RSA key pair. Since this isn’t a bundled mobile app, users would have to generate their own keys to get the token. Would it be possible to make this key pair optional if we are just redirecting back to the discourse app instead of a 3rd party? Likelihood of a man in the middle seems low, but I’m definitely unfamiliar with the requirements of this.
Keep in mind nothing is bundled, you hand the server your public key, it then encrypts your token using it. I know it may feel a bit overkill but I do not want to amend the protocol here. So when you “show” the api key to the user actually show the encrypted api key. Your CLI can then decrypt it cause it holds the private key.
hey everyone! A quick question. We have a development discourse set up, and I’m testing a call to request a (terminal given) token. So my question - what is a nonce? It looks like a unique id of some kind, but I’m wondering how / when / where it’s generated (so I can do it on behalf of my user, etc.) Thanks!
A nonce can be anything, a random string. You use is to protect against replay attack.
When we give you your encrypted payload you check the nonce matches the one you expect, if it does not well, someone is replaying an old encrypted token. Clearly for your use this level of security is … a bit … overkill…
Cool thanks! I’ll generate a uuid.uuid4() string. I think @fitz and I are probably close - he’s in a different time zone and we will touch bases soon, but hopefully we will have something working and for review! And if we have more questions, thank you again in advance for being so quick to help.
Makes the auth_redirect param optional, so that the payload will just be returned after the UserApiKey is created.
Does this look alright?
Should I add something to allow admins to disable this feature? Should I add some additional text to be displayed in the new.html.erb?