Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Targets for Pre-Saved Notification Sources #37

Open
RaminMT opened this issue Jan 13, 2021 · 16 comments
Open

Dynamic Targets for Pre-Saved Notification Sources #37

RaminMT opened this issue Jan 13, 2021 · 16 comments
Labels
question Further information is requested

Comments

@RaminMT
Copy link

RaminMT commented Jan 13, 2021

Question
Hi,
At first I must say thanks to who made this nice tool & also all the contributors and then the question
Is there anyway to only set credentials as configurations and the rest like chat ids or emails later when sending notification/message?

@RaminMT RaminMT added the question Further information is requested label Jan 13, 2021
@caronc
Copy link
Owner

caronc commented Jan 13, 2021

Absolutely,

But maybe not as granular as you'd like. You can run an NginX server in front of it. The Nginx configuration might look like this:

server {
    # To keep this example basic; we'll just listen on port 80
    listen  80;

    # Main Website/Relay
    location / {
       include uwsgi_params;
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_pass http://apprise-hostname-or-ip:8000;
       # Give ample time for notifications to fire
       proxy_read_timeout 120s;
    }

   # Here is the security portion you're asking for the place your site behind a password:
   auth_basic            "Restricted Area";
   auth_basic_user_file  apprise.htpasswd;
}

Now you just need to generate the apprise.htpasswd file.

# Generate a password file (-c option):
htpasswd -c /etc/nginx/apprise.htpasswd user1
# You'll be prompted for a password to associate with `user1`

# Now add future users too this way: (no -c because the db was already created):
htpasswd /etc/nginx/apprise.htpasswd user2
# You'll be prompted for a password to associate with `user2`

If you access your PC (assuming you've exposed port 80), you should be able to visit: http://pc-host-or-ip-with-nginx to access your Apprise service (and will be prompted for credentials).

Is this what you're asking? Or do you want like a user/pass combo to associate with individual {keys}. This does not exist at this time.

@RaminMT
Copy link
Author

RaminMT commented Jan 13, 2021

Thanks for quick & comprehensive response
But no, this wasn't what I was looking for. Let's assume we have a Telegram key configured in apprise like this:

tgram://VERY_SECRET_BOT_TOKEN?format=html

As you can see we didn't provide any telegram chat_id to our configuration, Now is there ability to set that chat_id while sending the message/notification? like this:

curl -X POST http://apprise-hostname:8000/notify/Telegram -H 'Content-Type: application/json' -d '{"urls": "/my_chat_id", "title": "the very dear title", "body": "The long message we have"}'

I used urls as an example.

@caronc
Copy link
Owner

caronc commented Jan 13, 2021

I see what you're saying. There is no way to do that. Not at this time anyway... I'd have to think about just passing variables back.
You could leverage Tagging and define a configuration file. In this case you chose Telegram as your key:

# Effectively I'm loading a persistent storage with the entries:
# syntax is tag(s)=<url>
# team,joe=tgram://joes-token?format=html
# team,jason=tgram://jasons-token?format=html

curl -X POST 'http://apprise-hostname:8000/add/Telegram' \
   -H 'Content-Type: application/json' \
   --data '{"format": "text", "config": " \
team,joe=tgram://joes-token?format=html \
team,jason=tgram://jasons-token?format=html"}'

Now we have 2 users defined each with their own tag (jason, and joe). But we can also team to notify both of them:

# Notify everyone (using tag keyword):
curl -X POST http://apprise-hostname:8000/notify/Telegram -H 'Content-Type: application/json' \
   -d '{"tag": "team", "title": "the very dear title", "body": "The long message we have"}'

# Just notify Jason:
curl -X POST http://apprise-hostname:8000/notify/Telegram -H 'Content-Type: application/json' \
   -d '{"tag": "jason", "title": "the very dear title", "body": "The long message we have"}'

Would this solve your problem? Or do you still see a good cause for variables? Thoughts?

@RaminMT
Copy link
Author

RaminMT commented Jan 13, 2021

The way you told already came to my mind, but that's a bit static and I'm looking for a dynamic way.
Actually there is no special reason for this 😄 I wanted to share the instance and some settings with some of my friends and they could use it as they like/need in a fire & forget manner
But an idea/cause is that we can use it simpler in our apps with caring about credentials etc, so we configure the apprise once and call it many times with passing just parameters.
Right now I don't have any idea that how could it be, but I think and share the idea as soon as I get one

@RaminMT
Copy link
Author

RaminMT commented Jan 13, 2021

If we config only one service per key (which is not guarantied) we can simply have receivers key in notification payload with array of ids or emails but that would be a bit complicated when having multiple services per key.
For multiple services per key maybe we can get help of tags like below:

curl -X POST http://apprise-hostname:8000/get/some-key-name
Telegram=tgram://VERY_SECRET_BOT_TOKEN?format=html
Mail=mailto://user:password@yahoo.com
FCM=fcm://project@APIKey

And

...
"receivers": {
  Telegram: ["chat_id1", "chat_id2", ..., "chat_idN"],
  Mail: ["Ramin@google.com", "Chris@github.com"]
  FCM: []
...

@caronc
Copy link
Owner

caronc commented Jan 14, 2021

I'm looking for a dynamic way.

Well... tgram://VERY_SECRET_BOT_TOKEN?format=html isn't that many more characters than VERY_SECRET_BOT_TOKEN. You could just skip the Persistent storage completely and just send your notification (all your friends can still use the same service):

# Send Notification (i notice you're specifying 'html' output, so set the `format=html` so that
# Apprise knows you're also feeding it `html` 
curl -X POST http://apprise-hostname:8000/notify -H 'Content-Type: application/json' \
   -d '{"format="html", "urls": "tgram://VERY_SECRET_BOT_TOKEN?format=html", "title": "the very dear title", "body": "The long message we have"}'

No /notify/Telegram needed (Persistent Storage). Just post to /notify with the Apprise URL instead. That achieves your dynamic request. You can also specify more then one URL (just separate them with spaces and/or commas:

# Send Notification (i notice you're specifying 'html' output, so set the `format=html` so that
# Apprise knows you're also feeding it `html` 
curl -X POST http://apprise-hostname:8000/notify -H 'Content-Type: application/json' \
   -d '{"format="html", "urls": "tgram://VERY_SECRET_BOT_TOKEN?format=html, tgram://ANOTHER_SECRET_BOT_TOKEN?format=html", "title": "the very dear title", "body": "The long message we have"}'

If we config only one service per key (which is not guarantied) we can simply have receivers key in notification payload with array of ids or emails but that would be a bit complicated when having multiple services per key.

You confused me a bit here 🙂 . I might need you to explain this again to me. You can identify more then one tag and associated it with a URL.

Just so we know we're talking about two things here (but i think i missed what you're asking):

  • tag is an Apprise thing (not specific to Apprise-API) where you can tag URLs within a configuration. You can set as many tag's as you want to a single URL.

    # A Text Based Configuration
    # The syntax per line is:
    #  url
    # tag=url
    # tag1,tag2,tagN=url
    
    # So you could define:
    friend,jason=tgram://jasons-token
    friend,arnold=tgram://arnolds-token
    friend,family,mike=mailto://mike:pass@gmail.com
    devops=slack://tokena/tokenb/tokenc
    family,mom=fcm://token/moms-cellphone-device
    cindy,family=mailto://cindy:pass@hotmail.com

    With the above, some URLs can now be referenced by more then one way. If you set the tag to be family, you'd notify 3 entries above. If you set the tag to all you'd notify everyone (that's a special keyword). All of these tags can be associated with a {key} on the Apprise API if you wanted. You can actually send to more than one person this way:

    # use a list instead of a single string when setting up the tag:
    # The below would send a notification to JUST cindy and mike (defined above)
    curl -X POST http://apprise-hostname:8000/notify/Telegram -H 'Content-Type: application/json' \
       -d '{"tag": ["cindy", "mike"], "title": "the very dear title", "body": "The long message we have"}'
  • {key} is exclusive to the Apprise-API and allows you to pre-save Apprise URL(s) to them. Within this configuration, you can leverage the tags if you wanted. If if were you, I'd keep all of your configuration under ONE {key}. The more {key}s you define, the more API requests you need to make. If you use tags, you can notify everyone you want in one go (one request).

@RaminMT
Copy link
Author

RaminMT commented Jan 14, 2021

Again I thank you and forgive me for making you confused
I'm aware of /notify endpoint but when using /notify we should deal with credentials like username & passwords or tokens, What I'm looking for is something similar to /notify but with concerns of credentials, is it clear?

@caronc
Copy link
Owner

caronc commented Jan 14, 2021

Yeah,

I hear you now....

Basically enable user authentication, and the {keys} are free-for all until claimed by the authenticated user. Then they're only available to them and locked from others to access.... something along those lines?

The only catch is the /notify/{key} gets a little bit more complicated because you'll have to either provide your user/password along with it (or have it stored in a session), or perhaps a key will automatically have an API key generated for it that you could pass in with the request s well?

Thoughts?

@RaminMT
Copy link
Author

RaminMT commented Jan 15, 2021

Excuse me, I didn't catch your sentences!
I guess I wasn't able to be clear.
Currently apprise has two way for sending message right?

  1. Send such a request to /notify:
curl -X POST -H 'Content-Type: application/json' http://apprise-hostname:8000/notify \
    -d '{"urls":"tgram://telegram_bot_token/my_chat_id", "title":"my notification title", "body":"my long & detailed notification body"}'
  1. Send such a request using {keys} to /notify/my-key:
curl -X POST -H 'Content-Type: application/json' http://apprise-hostname:8000/get/my-key
tgram://telegram_bot_token/my_chat_id
curl -X POST -H 'Content-Type: application/json' http://apprise-hostname:8000/notify/my-key \
    -d '{"title":"my notification title", "body":"my long & detailed notification body"}'

Correct?

Now what I am proposing/asking is ability to send notification like this:

curl -X POST -H 'Content-Type: application/json' http://apprise-hostname:8000/get/my-key
tgram://telegram_bot_token
curl -X POST -H 'Content-Type: application/json' http://apprise-hostname:8000/notify/my-key \
    -d '{"SOME_KEY": "my_chat_id", "title":"my notification title", "body":"my long & detailed notification body"}'

which that SOME_KEY can be for example receiver(s) so magically behind the scene the url will transformed to tgram://telegram_bot_token/my_chat_id which we currently set in {keys}

@caronc
Copy link
Owner

caronc commented Jan 15, 2021

@RaminMT,

I will think about this. It seems like a rather complicated request too accomplish something that's already solved.

I do understand your argument:

  • You want to keep all of the credentials pre-saved in the configuration but not the targets you wish to notify.
  • You want to dynamically pass in the target(s) as part of the request (instead of the full URL).

My argument back is that with the current design you can do this already. It just means you need to post tgram://token/target and not target like you're asking for.

I also understand that your saying you also want to be able to pass in more than one target too. You mentioned working with an array of targets (such as target1, target2, and target3, etc...). But again, I'm just curious you why you don't want to just post this as tgram://token/target1/target2/target3 in this case then too?

Effectively:

  • Prepend tgram://token/ to your targets
  • Optionally append ?format=html as you were using in your earlier examples after your targets.

Here is a simple dynamic bash example, but you can easily port the same logic into Python, Go, Rust, PHP, etc:

#/bin/sh
# Dynamic Telegram Notifier Script
#  Syntax:
#      # just notify `target1`
#      script.sh target1
#      # Notify all our predefined targets (inside the script)
#      script.sh
#      # Notify 5 targets (one API call)
#      script.sh target1 target2 target3 target4 target5

# Set our targets to whatever was passed into the script
TARGETS=$@

# If there were no targets defined, use a default list
[ -z "$TARGETS" ] && TARGETS="
  abcd \
  defg \
  hijk \
"
# Set our telegram token
TOKEN="abcd-12234"

# Dynamically turn our targets into path based entries
# target1/target2/target3/targetN/....
URLPATH=$(echo $TARGETS | sed -e 's|[[:space:]]\+|/|g')
if [ ! -z "$URLPATH" ]; then
   # If we have anyone to notify, do so:
   URL="tgram://$TOKEN/$URLPATH/?format=html"
   curl -X POST -H 'Content-Type: application/json' \
      http://apprise-hostname:8000/notify \
    -d '{"urls":"$URL", "title":"my notification title", "body":"my long & detailed notification body"}'
fi
  • If you already know the users/targets in advance, then it's best that you pre-define them and tag them with the user who owns it. I realize this isn't dynamic though with respect to what you're trying to do.
  • If you're randomly messaging people with random chat_id's you don't yet know, then i suggest you construct a URL dynamically and notify them. This seems to be kind of what your describing that you want to do.

Does this help at all? If you're still certain your request should be put into the Apprise-API code, can you just give me a use-case for it? I'm sorry that I've dragged this out for so long 🙂 . I'm just trying to understand the problem you're trying to solve and why you can't use the way that already exists and works?

I foresee lots of issues by having the configuration file suddenly become dynamic. Configuration files are usually static; you set them up and let them be. If you want to dynamically work with the tool, then you just need to send it dynamically generated URLs.

Thoughts?

@caronc caronc changed the title config without chat_id or etc Dynamic Targets for Pre-Saved Notification Sources Jan 15, 2021
@RaminMT
Copy link
Author

RaminMT commented Jan 16, 2021

Hi again
I like the new title, this is more meaningful
Seems we both finally managed to mean each other. At first I came here just to know if such thing is possible natively or no, then I thought you need some initial idea of how to add this so I proposed what you mentioned (array of targets etc).
I think that's ok if you're not going to add this for whatever reason it is. I wanted to have a key (named Telegram for example) pre-saved in my configurations and let my friends use it to send messages to whoever they want, that was my use-case and so this is exactly the second situation you described. I also imagined another use-case but you already described a solution for it too.
I think even with this feature (?) still the configurations are static cause they just carry the credentials, I think currently with setting the targets in configuration it is more dynamic than static, because maybe someone apply regular updates just because of targets. Finally I feel the most use-case of this nice tool is to be used at staging environments or inside teams rather than production environments (which is absolutely work well there too)

@caronc
Copy link
Owner

caronc commented Jan 17, 2021

I think that's ok if you're not going to add this for whatever reason it is.

I'll think about it... At this time the idea doesn't really work because the only advantage i can see is if there was a way to create a private configuration file (hiding your personal credentials) and allowing users to just leverage the use of it (without knowing them). The thing is, the way Apprise-API works today is if you put your token into the configuration and share it with someone else, they can very easily access these details (so it's not protected). If your friends have your {key} and access to your Apprise-API, they just have to do the following to get all of your details:

# A nice ordered response of your configuration; this makes writing your own
# front end API around Apprise very easy
curl http://apprise-hostname:8000//json/urls/{KEY}

# The method you already know about; this is actually what the Apprise
# CLI tool leverage's in order to fetch information from remote servers
curl -X POST  http://apprise-hostname:8000/get/{KEY}

Until the above commands are buried behind authentication associated with the {key}, there is no value in storing partial configuration that won't work without extra provided payload as you're suggesting. Do you see where I'm coming from?

, I think currently with setting the targets in configuration it is more dynamic than static, because maybe someone apply regular updates just because of targets.

This was why I was saying to not use a fixed configuration if your data is dynamic; just dynamically generate the URL around the entries.

Anyway, I'll leave this ticket open. Maybe someone else who might be scanning/browsing through will have comments or suggestions. I can see your idea; i just don't want to rush into it's execution because I think there might be alternative ways to handle it (or maybe another way we can enhance the code that will still help you out! 🙂

@RaminMT
Copy link
Author

RaminMT commented Jan 18, 2021

Firstly I thank you again for your patience and efforts you put on this topic.

At this time the idea doesn't really work because the only advantage i can see is if there was a way to create a private configuration file (hiding your personal credentials) and allowing users to just leverage the use of it (without knowing them).

This is completely correct.

The thing is, the way Apprise-API works today is if you put your token into the configuration and share it with someone else, they can very easily access these details (so it's not protected).

This is also correct, but I already managed this with changing the routes, I routed everything to /notify and /web to / (which shows web panel or let access to the api 😄

Anyway, I'll leave this ticket open. Maybe someone else who might be scanning/browsing through will have comments or suggestions. I can see your idea; i just don't want to rush into it's execution because I think there might be alternative ways to handle it (or maybe another way we can enhance the code that will still help you out! 🙂

Very good, thanks again

@sonuame
Copy link

sonuame commented Mar 14, 2023

Sorry for being late to the party, I am in process to implement this for one of my project and I really loved the concept of apprise. Its a wonderful product.

However, I am stuck at the very same scenario now. I have a signal rest server running and we shoot messages to all of my new clients whenever needed from an automated solution.

I want to trigger signal via apprise now and I didn't find a way to dynamically assign the receivers phone number via apprise. I can't save them statically inside configs.

@caronc
Copy link
Owner

caronc commented Aug 3, 2023

This request has come back several times now, so i'll have to reconsider it.

I'm thinking:

# Text Configuration
mailto://credentials/{{email}}

or yaml

urls:
  - mailto://credentials/{{email}}

Or even:

urls:
  - mailto://credentials:
    to: {{email}}

the problem is that Apprise will very much choke on this configuration, so the underlining libary is going to need a new variable in the AppriseAsset object that states something like templating = False. Disabled by default.

But when it's enabled, anything you put in the {{varname}} will be required to be passed into the post request. & will have to be escaped if found in the URL so it doesn't cause any injections

curl -X POST \
    -F 'varname=user@gmail.com' \
    -F 'body=test message' \
  http://apprise-hostname:8000/notify/my-key

The above would extrapolate varname as not being one of the defaults (body, title, format, etc) and apply a swap of any {{varname}} elements found with what it matches against before loading it into Apprise.

Because the {{tokens}} will break Apprise, i feel that the bulk of this templating should probably be done in the core library itself and not the API website. The alternative is I do it in the API, but remove all validation of the config files which takes place after you save it. All Config files would just be presumed valid until the time comes to send the notification; then the front end (API itself) would do the {{token}} swapping on each request.

Thoughts?

@akelge
Copy link

akelge commented May 3, 2024

I have to raise this ticket again.
We are evaluating the use of Apprise in our internal processes and we hit the same wall.
What I am thinking is to be able to define some base destinations, leaving some extra parameters to be added at the moment we call /notify.

I can understand there are several implications, but that can be beneficial both using the API server or running from CLI or from python. Even locally I can define some basic service, like email server parameters, and then use it just passing in the parameters also the to field.

This way Apprise API server will become a notification HUB with more flexibility.

In our use case, for example, we want to send email, slack and teams notification. We could define

email: mailto://server?parameters
slack: slack://token1/token2/token3
teams: teams://whatever is needed

and then use
apprise -b "body of notification" -t "title" "apprise://apprise.server:8000/apprise/?tags=email&destination=whatever"
or
apprise -b "body of notification" -t "title" "apprise://apprise.server:8000/apprise/?tags=slack&desitnation=#achannel"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants