Skip to content

Commit

Permalink
Merge branch 'dev-tbyte'
Browse files Browse the repository at this point in the history
  • Loading branch information
antt1995 committed Feb 13, 2025
2 parents a9fe932 + 9965bfa commit 301d851
Show file tree
Hide file tree
Showing 28 changed files with 421 additions and 370 deletions.
5 changes: 3 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ group :development, :test do
# Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
gem "rubocop-rails-omakase", require: false

gem "erb_lint", "~> 0.9.0"
gem "i18n-tasks", "~> 1.0.14", require: false

gem "erb_lint", "~> 0.9.0", require: false
gem "standardrb", "~> 1.0"
end

Expand Down Expand Up @@ -101,7 +103,6 @@ gem "kaminari", "~> 1.2"
gem "invisible_captcha", "~> 2.3"

gem "devise-i18n"
gem "i18n-tasks", "~> 1.0.14" # , group: :development
gem "rails-i18n", "~> 7.0.10"
gem "translation"

Expand Down
10 changes: 5 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ GEM
autoprefixer-rails (10.4.19.0)
execjs (~> 2)
aws-eventstream (1.3.0)
aws-partitions (1.1049.0)
aws-partitions (1.1050.0)
aws-sdk-core (3.218.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
Expand Down Expand Up @@ -496,14 +496,14 @@ GEM
chunky_png (~> 1.0)
rqrcode_core (~> 1.0)
rqrcode_core (1.2.0)
rubocop (1.70.0)
rubocop (1.71.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.36.2, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.38.0)
Expand Down Expand Up @@ -572,10 +572,10 @@ GEM
sprockets (>= 3.0.0)
sqlite3 (2.5.0)
mini_portile2 (~> 2.8.0)
standard (1.44.0)
standard (1.45.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.70.0)
rubocop (~> 1.71.0)
standard-custom (~> 1.0.0)
standard-performance (~> 1.6)
standard-custom (1.0.2)
Expand Down
64 changes: 47 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,24 @@ Hosted at [pwpush.com](https://pwpush.com) but you can also easily run your own
* __Audit logging:__ Track and control what you've shared and see who has viewed it.
* __Encrypted storage:__ All sensitive data is stored encrypted and deleted entirely once expired.
* __Host your own:__ Database backed or ephemeral, easily run your own instance isolated from the world.
* __JSON API:__ Raw JSON API available for 3rd party tools or command line via `curl` or `wget`.
* __Command line interface:__ Automate your password distribution with CLI tools or custom scripts.
* __Logins__: Invite your colleagues and track what is pushed and who retrieved it.
* __Admin Dashboard:__ Manage your self-hosted instance with a built in admin dashboard.
* __Logins__: Invite your colleagues and track what is pushed and who retrieved it.
* __Unbranded delivery page:__ No logos, superfluous text or unrelated links to confuse end users.
* __Internationalized:__ 29 language translations are bundled in. Easily selectable via UI or URL
* __JSON API:__ Raw JSON API available for 3rd party tools or command line via `curl` or `wget`.
* __Command line interface:__ Automate your password distribution with CLI tools or custom scripts.
* __Themes:__ [26 themes](https://docs.pwpush.com/docs/themes/) bundled in courtesy of [Bootswatch](https://github.com/thomaspark/bootswatch). Select with a simple environment variable.
* __Unbranded delivery page:__ No logos, superfluous text or unrelated links to confuse end users.
* __Customizable:__ Change text and default options via environment variables.
* __Light & dark themes:__ Via CSS @media integration, the default site theme follows your local preferences.
* __Re-Brandable:__ Customize the site name, tagline and logo to fit your environment.
* __Re-Brandable:__ Completely white label: customize the theme, site name, tagline and logo to fit your environment.
* __Custom CSS:__ Bundle in your own custom CSS to add your own design.
* __>10 Years Old:__ Password Pusher has securely delivered millions and millions of passwords in its 10 year history.
* __>10 Years Old:__ Password Pusher has securely delivered millions and millions of passwords in its 14 year history.
* __Actively Maintained:__ I happily work for the good karma of the great IT/Security community.
* __Honest Software:__ Open source written and maintained by [me](https://github.com/pglombardo) with the help of some great contributors. No organizations, corporations or evil agendas.

💌 --> Sign up for [the newsletter](https://buttondown.email/pwpush?tag=github) to get updates on big releases, security issues, new features, integrations, tips and more.

Password Pusher is also [on Twitter](https://twitter.com/pwpush), [Gettr](https://gettr.com/user/pwpush) and [on Facebook](https://www.facebook.com/pwpush)
Follow Password Pusher updates on [X](https://x.com/pwpush), [Reddit](https://www.reddit.com/r/pwpush), [Gettr](https://gettr.com/user/pwpush) and [Facebook](https://www.facebook.com/pwpush).

-----

Expand All @@ -60,25 +60,23 @@ Password Pusher is also [on Twitter](https://twitter.com/pwpush), [Gettr](https:

# Editions

If you wish the self-host, this open source version is available immediately. You can try it out at [https://oss.pwpush.com](https://oss.pwpush.com) or read on for how to get started.
If you are considering to self-host the OSS edition, you can try it out immediately at [https://oss.pwpush.com](https://oss.pwpush.com).

In 2024, I introduced a set of **Pro features** exclusively on [pwpush.com](https://pwpush.com) to better support the project.

In 2024, I introduced a set of **Pro features** exclusively on [pwpush.com](https://pwpush.com) to better support the project. These Pro features are part of the new _Feature Pipeline_ and are migrated to the OSS edition periodically over time. You can read more about how this works [here](https://docs.pwpush.com/docs/editions/).
These Pro features are periodically migrated to the OSS edition. You can read more about how this works [here](https://docs.pwpush.com/docs/editions/).

To see the differences between pwpush.com and the OSS edition take a look at the [Feature Matrix](https://pwpush.com/features#matrix).

# ⚡️ Quick Start

→ Go to [https://pwpush.com](https://pwpush.com) and try it out.

_or_

→ Run your own instance with `docker run -d -p "5100:5100" pglombardo/pwpush:latest` or a [production ready setup with a database & SSL/TLS](https://github.com/pglombardo/PasswordPusher/tree/master/containers/docker/all-in-one).
→ Run your own instance with `docker run -d -p "5100:5100" pglombardo/pwpush:stable` or a [production ready setup with a database & SSL/TLS](https://github.com/pglombardo/PasswordPusher/tree/master/containers/docker/all-in-one).

_or_

→ Use one of the [3rd party tools](https://docs.pwpush.com/docs/3rd-party-tools/) that interface with Password Pusher.

# Documentation
# 📚 Documentation

See the full [Password Pusher documentation here](https://docs.pwpush.com).

Expand Down Expand Up @@ -137,6 +135,38 @@ Thanks to:

...and many more. See the [Contributors page](https://github.com/pglombardo/PasswordPusher/graphs/contributors) for more details.

# 🎁 Donations

Donations are in no way required of any Password Pusher user. The project, at it's core, is and always has been open source and free to use.

With that said, if you find Password Pusher useful and would like to support & accelerate it's continued development all donations are _greatly appreciated_.

| [![Donate](https://pwpush.fra1.cdn.digitaloceanspaces.com/misc/pwpush-donate-stripe-qr-small.png)]() | or | [![Donate](https://img.shields.io/badge/Donate-Stripe-blue.svg)](https://buy.stripe.com/7sI4gCgTT1tr6WY3cd) |
|---|---|---|


As an alternative to donations, you can also support the project by signing up for a [paid plan at pwpush.com](https://pwpush.com/pricing).

Donations are used to pay for the following:

* Hosting costs (Digital Ocean, Hatchbox, Brevo Support & Transactional Email, Docker Hub, Uptime Robot)
* Community Support
* On-going Maintenance
* Upgrades
* Testing
* Continued development
* Development tools
* License costs
* Documentation

**Legal Disclaimer:** Please note that Password Pusher is owned and operated by Apnotic, LLC, a for-profit company owned and operated by [me](https://github.com/pglombardo). While donations are greatly appreciated and help support the project's development, they are not tax deductible as charitable contributions. Donations made to Password Pusher directly support a commercial entity and should be viewed as a voluntary payment to help sustain the service and encourage continued development.

**See Also:**

* [What is Apnotic, LLC?](https://docs.pwpush.com/docs/faq/#what-is-apnotic)
* [Trust is a concern. Why should I trust and use Password Pusher?](https://docs.pwpush.com/docs/faq/#trust-is-a-concern--why-should-i-trust-and-use-password-pusher)
* [How does the Pro feature pipeline work?](https://docs.pwpush.com/posts/feature-pipeline/)

# 🛡 License

[![License](https://img.shields.io/github/license/pglombardo/PasswordPusher)](https://github.com/pglombardo/PasswordPusher/blob/master/LICENSE)
Expand All @@ -148,8 +178,8 @@ This project is licensed under the terms of the `Apache License 2.0` license. Se
```bibtex
@misc{PasswordPusher,
author = {Peter Giacomo Lombardo},
title = {An application to securely communicate passwords over the web. Passwords automatically expire after a certain number of views and/or time has passed.},
year = {2024},
title = {Securely share sensitive information with automatic expiration & deletion after a set number of views or duration. Track who, what and when with full audit logs.},
year = {2025},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/pglombardo/PasswordPusher}}
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.50.14
1.50.18
17 changes: 0 additions & 17 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,3 @@ import "@hotwired/turbo-rails"
import "@rails/activestorage"
import "bootstrap"
import "./controllers"

const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");

// Function to handle theme changes
const handleThemeChange = (e) => {
if (e.matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark')
} else {
document.documentElement.setAttribute('data-bs-theme', 'light')
}
}

// Initial check
handleThemeChange(prefersDarkScheme);

// Listen for changes
prefersDarkScheme.addEventListener('change', handleThemeChange);
2 changes: 2 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import KnobsController from "./knobs_controller"
import MultiUploadController from "./multi_upload_controller"
import PWGenController from "./pwgen_controller"
import PasswordsController from "./passwords_controller"
import ThemeController from "./theme_controller"
import { application } from "./application"

application.register("gdpr", GdprController)
Expand All @@ -14,3 +15,4 @@ application.register("form", FormController)
application.register("knobs", KnobsController)
application.register("passwords", PasswordsController)
application.register("multi-upload", MultiUploadController)
application.register("theme", ThemeController)
27 changes: 27 additions & 0 deletions app/javascript/controllers/theme_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {

connect() {
this.prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)")

// Initial check
this.handleThemeChange(this.prefersDarkScheme)

// Listen for changes
this.prefersDarkScheme.addEventListener('change', this.handleThemeChange.bind(this))
}

disconnect() {
// Clean up event listener when controller disconnects
this.prefersDarkScheme.removeEventListener('change', this.handleThemeChange.bind(this))
}

handleThemeChange(e) {
if (e.matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark')
} else {
document.documentElement.setAttribute('data-bs-theme', 'light')
}
}
}
13 changes: 13 additions & 0 deletions app/views/application/_ip_address.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<% begin %>
<% ip.split(',').each do |single_ip| %>
<% single_ip = single_ip.strip %>
<% if IPAddr.new(single_ip).private? || IPAddr.new(single_ip).loopback? %>
<strong><%= single_ip %></strong>
<% else %>
<strong><%= link_to single_ip, "https://iplocation.io/ip/#{single_ip}", target: '_blank' %></strong>
<% end %>
<%= ',' unless single_ip == ip.split(',').last %>
<% end %>
<% rescue StandardError %>
<%= ip %>
<% end %>
13 changes: 8 additions & 5 deletions app/views/file_pushes/audit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,13 @@
<% if view.user_id %>
<%= _('Password manually expired by user') %>
<strong><%= view.user.email %></strong>
<%= _('at IP address') %> <strong><%= view.ip %></strong>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<% else %>
<%= _('Password manually expired by an anonymous user') %>
<% end %>
<%= _('at IP address') %>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
<%= _('The push content has been deleted and the secret URL expired.') %>
<br>
Expand All @@ -261,7 +264,7 @@
<div class="list-group-item list-group-item-action list-group-item-success">
<em class="bi bi-check2-square"></em>
<%= _('Successful view from IP address') %>
<strong><%= view.ip %></strong>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
Expand All @@ -273,7 +276,7 @@
<div class="list-group-item list-group-item-action list-group-item-warning">
<em class="bi bi-x-octagon"></em>
<%= _('Failed view attempt (already expired) by') %>
<strong><%= view.ip %></strong>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<html lang="<%= I18n.locale %>" data-controller="theme">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/bare.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<html lang="<%= I18n.locale %>" data-controller="theme">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/login.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<html lang="<%= I18n.locale %>" data-controller="theme">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/naked.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<html lang="<%= I18n.locale %>" data-controller="theme">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Expand Down
14 changes: 7 additions & 7 deletions app/views/passwords/audit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,13 @@
<% if view.user_id %>
<%= _('Password manually expired by user') %>
<strong><%= view.user.email %></strong>
<%= _('at IP address') %> <strong><%= view.ip %></strong>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<% else %>
<%= _('Password manually expired by an anonymous user') %>
<%= _('Password manually expired by an anonymous user') %>
<% end %>
<%= _('at IP address') %> <strong><%= view.ip %></strong>
<%= _('at IP address') %>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
<%= _('The push content has been deleted and the secret URL expired.') %>
<br>
Expand All @@ -195,7 +195,7 @@
<div class="list-group-item list-group-item-action list-group-item-success">
<em class="bi bi-check2-square"></em>
<%= _('Successful view from IP address') %>
<strong><%= view.ip %></strong>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
Expand All @@ -207,7 +207,7 @@
<div class="list-group-item list-group-item-action list-group-item-warning">
<em class="bi bi-x-octagon"></em>
<%= _('Failed view attempt (already expired) by') %>
<strong><%= view.ip %></strong>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
Expand Down
7 changes: 4 additions & 3 deletions app/views/urls/audit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@
<% if view.user_id %>
<%= _('URL Push manually expired by user') %>
<strong><%= view.user.email %></strong>
<%= _('at IP address') %> <strong><%= view.ip %></strong>
<%= _('at IP address') %>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<% end %>
<br>
<%= _('The push content has been deleted and the secret URL expired.') %>
Expand All @@ -177,7 +178,7 @@
<div class="list-group-item list-group-item-action list-group-item-success">
<em class="bi bi-check2-square"></em>
<%= _('Successful view from IP address') %>
<strong><%= view.ip %></strong>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
Expand All @@ -189,7 +190,7 @@
<div class="list-group-item list-group-item-action list-group-item-warning">
<em class="bi bi-x-octagon"></em>
<%= _('Failed view attempt (already expired) by') %>
<strong><%= view.ip %></strong>
<%= render partial: 'application/ip_address', locals: { ip: view.ip } %>
<%= _('on') %>
<%= I18n.l view.created_at.in_time_zone(Settings.timezone) %>
<br>
Expand Down
2 changes: 1 addition & 1 deletion config/defaults/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ files:
# * microsoft - use Microsoft Azure Storage (and provide 'as' credentials below)
#
# Environment variable override:
# PWP__FILES_STORAGE='local'
# PWP__FILES__STORAGE='local'
#
storage: 'local'

Expand Down
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@

root to: "passwords#new"
end

# Health check endpoint that returns a simple 200 OK response
get "/up" => proc { |env|
[200, {"Content-Type" => "text/html"}, ["<html style='background:green;width:100%;height:100vh'></html>"]]
}
end
Loading

0 comments on commit 301d851

Please sign in to comment.