Determine how many days a certificate is still valid from within bash script - bash

I want to check how many days the certificate of a website is valid from within a bash script which runs on a standard Ubuntu 14.04 server. openssl is available.
I already figured out that I can use openssl to get the target date
$ echo | openssl s_client -connect google.com:443 2>/dev/null|openssl x509 -noout -enddate
notAfter=Dec 22 16:37:00 2016 GMT
But how do I parse the resulting date and subtract the current one? Or might there be a better solution?

Just in single line
echo "(" $(date -d "`openssl x509 -in /etc/letsencrypt/live/d-herrmann.de/cert.pem -text -noout | grep "Not After" | cut -c 25-`" +%s) - $(date -d "now" +%s) ")" / 86400 | bc

With GNU date's %j to get day of the year and arithmetic expansion for subtraction:
$ echo $(( $(date -d "$(cut -d= -f2 <(echo 'notAfter=Dec 22 16:37:00 2016 GMT'))" '+%j') - $(date '+%j')))
73
$(date -d "$(cut -d= -f2 <(echo 'notAfter=Dec 22 16:37:00 2016 GMT'))" '+%j') gets us the day of the year from the date we have got, replace teh echo command inside process substitution, <(echo 'notAfter=Dec 22 16:37:00 2016 GMT') with the openssl command you have used initially
$(date '+%j') gets us today's date as day of the year
$(()) is used for subtracting the integers

date1="Dec 22 16:37:00 2016 GMT" # Future date
date2=$(date) # Current date
diff=$(($(date -d "$date1" +%j)-$(date -d "$date2" +%j))) #Diff between two date, %j is to show day of the year.
echo $diff #Display difference
73
Or just in one line:
echo $(($(date -d "Dec 22 16:37:00 2016 GMT" +%j)-$(date +%j)))
73

Here is a little script, which returns days, hours or minutes a cert is still valid, I just saved it in an executable file e.g. check_cert_age.sh
#!/bin/bash
# input domain as first parameter eg. ./heck_cert_age.sh stackoverflow.com
input="$1"
domain=$(echo "$input" | sed -e 's|^[^/]*//||' -e 's|/.*$||')
#domain=stackoverflow.com
echo
echo "Check the cert of Domain $domain"
datetime=$(timeout 5 openssl s_client -servername $domain -connect $domain:443 2>/dev/null | openssl x509 -noout -dates | sed 's/notAfter=\(.*\)$/\1/' | tail -n1)
if [ -z "$datetime" ]; then
echo
echo "ERROR"
echo
exit 0
fi
localtime=$(date -d "${datetime}" '+%R')
localdate=$(date -d "${datetime}" '+%Y-%m-%d')
timestamp=$(date -d "${datetime}" '+%s')
now=$(date '+%s')
diff=$((($timestamp-$now)/60))
if [ "$diff" -gt 3599 ] || [ "$diff" -lt 3599 ]; then
diffstr="$(expr $diff / 60 / 24) days"
elif [ "$diff" -gt 59 ] || [ "$diff" -lt 59 ] ; then
diffstr="$(expr $diff / 60) h"
else
diffstr="$diff min"
fi
echo
echo "The cert is valid until $localdate at $localtime ($diffstr)"
echo
The output will be:
Check the cert of Domain stackoverflow.com
The cert is valid until 2023-02-01 at 15:10 (50 days)
The output make a difference in days, hours, minutes and knows the difference to the local timezone. For minutes, it would look e.g. like that:
Check the cert of Domain ssl-cert-almost-expired.com
The cert is valid until 2022-12-13 at 15:39 (34 min)

Related

How to get second sunday in a Month given a date parameter in bash script

I am trying to write a bash script, to merge 24 files in a given day. The requirement changes during Day light saving time changes, where I get 23 or 25 files.
So, with further research I realized that day-light savings begins on the second Sunday of March(23) of every year and ends on first sunday of Novemeber(25).
I need more inputs to get second sunday in a given month to do the check of finding 23 or 25 files for March and November respectively.
Any inputs to help me with this will be really appreciated.
Thank you
Here is the sample code to find 24 files in a day-
if [ -z "$1" ];then
now=$(date -d "-1 days" +%Y-%m-%d);
else now=$1;
fi
load_date='load_date='$now
singlePath="$newPath/$load_date"
fileCount=$(hdfs dfs -ls -R $hdfsPath/$load_date/ | grep -E '^-' | wc -l)
path=$hdfsPath/$load_date
if [ $fileCount -eq 24 ]; then
echo "All files are available for "$load_date;
hadoop fs -cat $path/* | hadoop fs -put - $singlePath/messages.txt
else echo $fileCount" files are available for "$load_date"! Please note, few files are being missed";
fi
I wouldn't hardcode the dates of DST transistions. I would just count "how many hours did today have":
a "normal" day:
$ diff=$(( $(date -d now +%s) - $(date -d yesterday +%s) ))
$ echo $(( diff / 3600 ))
24
"spring forward"
$ diff=$(( $(date -d "2019-03-10 23:59:59" +%s) - $(date -d "2019-03-09 23:59:59" +%s) ))
$ echo $(( diff / 3600 ))
23
"fall back"
$ diff=$(( $(date -d "2019-11-03 23:59:59" +%s) - $(date -d "2019-11-02 23:59:59" +%s) ))
$ echo $(( diff / 3600 ))
25
One thing to note: since bash only does integer arithmetic, if the difference is not 86400 but 86399, you get:
$ echo $((86399 / 3600))
23
So, better to query yesterday's time first in the tiny-but-non-zero chance that the seconds tick over between the 2 date calls:
diff=$(( -$(date -d yesterday +%s) + $(date -d now +%s) ))
Here, $diff will be 86400 or 86401 (for non DST transition days), and dividing by 3600 will give 24 not 23.

Linux Extract login history of all users

I currently have this bash script that is able to extract login history of all users in a certain time period, but I am trying to do so for all history not just between a certain time period.
Would it be more beneficial to grab this data from /var/log/secure?
Can anyone help steer me in the right direction?
last | while read line
do
date=`date -d "$(echo $line | awk '{ print $5" "$6" "$7 }')" +%s`
[[ $date -ge `date -d "Aug 25 00:00" +%s` && $date -le `date -d "Aug 28 00:00" +%s` ]] && echo $line
done
For the whole history just run last
Or
from last --help
-s --since
-t --until
Ex:
last -s 2019-01-30
For older login history you can try
last -s YYYY-MM-DD -f /var/log/wtmp.1 #

How to subtract today's date with a file's modification date in unix?

For example:
echo $(date) - $(date -r sample.txt)
Output:
90 days(for example)
Use %s seconds since 1970-01-01 00:00:00 UTC as in
echo $(expr $(date +%s) - $(date -r sample.txt +%s)) #!/bin/sh
echo $(($(date +%s) - $(date -r sample.txt +%s))) #/bin/bash
One more way
$ ls -l peter.txt
-rwxrw-r--+ 1 pppp qqqq 149 Dec 15 18:39 peter.txt
$ echo "(" $(date +%s) - $(date -r peter.txt +%s) ")/" 86400 | perl -nle ' print eval, " days" '
29.254537037037 days
$

Date comparison with EPOCH to find an expiry in bash script

#!/bin/bash
for ADDR in `netstat -plant|grep LISTEN|grep http|awk '{print $4}'|egrep -v ':80$|:5555$'|sort -u`; do
EXPDATE=`openssl s_time 2>/dev/null | openssl s_client -connect $ADDR 2>/dev/null | openssl x509 -dates 2>/dev/null | grep ^notA | cut -f2 -d= | sed -e "s/ GMT//"`
printf "\t\t\t|%s\t|%s\t|\t%s\t|\n" "$ADDR" "$EXPDATE"
done
EXPDATES="$(echo "$EXPDATE" | awk '{print $1,$2,$4,$3}')"
CURREPOCH="$(date +%s)"
for i in "$EXPDATES"; do
CREXPEPOCH="$(date +%s -d "$i")"
if [[ "$CURREPOCH" -gt "$CREXPEPOCH" ]]; then
echo "No Expiry Found."
else
echo "Cert expired"
fi
done
Here, I'm getting dates from EXPDATE which has multiple date values as shown below,
Jul 12 12:00:00 2019
Jun 18 12:00:00 2019
May 8 00:00:00 2018
Nov 14 00:00:00 2017
And, converting to EPOCH time for better comparison with current EPOCH..
If any past date found, script should return "expired", else "no expiry found"..
I tried above script which is not working..
How I can do that? Any help?
The below tracks contents in an array rather than trying to abuse strings as iterable.
#!/usr/bin/env bash
# return all addresses that smell like HTTP
get_addrs() {
netstat -plant \
| awk '/LISTEN/ && /http/ && ! ($4 ~ /:(80|5555)$/) { print $4; }' \
| sort -u
}
# Given a local server address, return a usable client address
# converts wildcard addresses to loopback ones.
clientAddr() {
local addr=$1
case $addr in
0.0.0.0:*) addr=127.0.0.1:${addr#0.0.0.0:} ;;
:::*) addr='localhost:'"${addr#:::}" ;;
esac
printf '%s\n' "$addr"
}
# Given a local address that runs a HTTPS server, return the last valid date for its certificate
endDateForAddr() {
local addr endDate
addr=$(clientAddr "$1") || return
endDate=$(openssl s_client -connect "${addr}" </dev/null 2>/dev/null \
| openssl x509 -dates \
| awk -F= '/^notAfter/ { print $2; exit }')
[[ $endDate ]] && printf '%s\n' "$endDate"
}
# Loop over our local HTTPS services...
expDates=( )
while read -r addr; do
# find an address we can use to refer to each...
addr=$(clientAddr "$addr") || continue
# ...and use that to find its certificate expirey date.
result=$(endDateForAddr "$addr") || continue
# then add that to our array.
expDates+=( "$result" )
done < <(get_addrs)
# in bash 4.3, this is more efficiently written: printf -v curr_epoch '%(%s)T' -1
curr_epoch="$(date +%s)"
for expdate in "${expDates[#]}"; do
exp_epoch=$(date +%s -d "$expdate")
if (( curr_epoch > exp_epoch )); then
echo "$expdate is in the past"
else
echo "$expdate is in the future"
fi
done
...its output (correct as of this writing):
Jul 12 12:00:00 2019 is in the future
Jun 18 12:00:00 2019 is in the future
May 8 00:00:00 2018 is in the future
Nov 14 00:00:00 2017 is in the future

How can I find time difference between two server timestamps?

This outputs the closest Google server's time:
// Closest Google Server:
date +"%s" -d "$(curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g')"
// Result: 1234
This outputs my local server time:
// Server
date +"%s"
// Result: 1235
How can I fetch the seconds between each result? (in the example above: 1)
Strictly answering your question, how about:
echo $(( $(date +"%s") - $(date +"%s" -d "`curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g'`") ))

Resources