In this article we will use jsonip and https://iplist.cc in order to gather data the requester’s ip address
https://jsonip.com is a simple JSON-based API that returns the client’s IP address in a JSON object. It is useful for getting the client’s IP address in a web application.
Here is an example response from https://jsonip.com:
{
"ip": "123.456.789.012"
}
You can send a GET request to https://jsonip.com to retrieve the client’s IP address. The response will be a JSON object with a single field, “ip”, which contains the client’s IP address as a string.
https://iplist.cc is a website that provides an API for retrieving information about an IP address. The API is a simple JSON-based API that returns a variety of information about the specified IP address, such as the country, region, city, time zone, latitude and longitude, and ASN (Autonomous System Number) information.
You can send a GET request to https://iplist.cc/api/{ip}, where {ip} is the IP address you want to look up, to retrieve information about the IP address. The response will be a JSON object containing the information about the IP address.
Here is an example response from https://iplist.cc/api/123.456.789.012:
{
"ip": "123.456.789.012",
"registry": "ARIN",
"countrycode": "US",
"countryname": "United States",
"asn": {
"code": "AS7922",
"name": "Comcast Cable Communications, Inc.",
"route": "123.456.0.0/16",
"start": "123.456.0.0",
"end": "123.456.255.255",
"count": "65536"
},
"spam": false,
"tor": false,
"city": "Chicago",
"detail": "Illinois, United States",
"website": [
"comcast.com"
]
}
First we will implement the requests using https (built-in node module).
By wrapping the request in a promise, we can still use async functions in javascript and handle errors accordingly.
In the future, we can build a wrapper around the promise to handle timeouts.
import {IPResponse} from './types'
import https from 'https'
export async function getIpAddress(): Promise<string> {
return new Promise((resolve, reject) => {
https.get('https://jsonip.com', res => {
res.setEncoding('utf8')
let body = ''
res.on('data', data => {
body += data
})
res.on('end', () => {
const json = JSON.parse(body)
resolve(json.ip)
})
res.on('error', error => {
reject(error)
})
})
})
}
export const getIpInfo = async (ip: string): Promise<IPResponse> => {
return new Promise((resolve, reject) => {
https.get(`https://iplist.cc/api/${ip}`, res => {
res.setEncoding('utf8')
let body = ''
res.on('data', data => {
body += data
})
res.on('end', () => {
const json = JSON.parse(body)
resolve(json)
})
res.on('error', error => {
reject(error)
})
})
})
}
This code defines two functions: getIpAddress and getIpInfo.
getIpAddress makes an HTTPS GET request to the https://jsonip.com endpoint and returns the ip field from the response in JSON format as a string.
getIpInfo makes an HTTPS GET request to the https://iplist.cc/api/[ip] endpoint, where [ip] is the value passed as an argument to the function. It returns the entire response from the endpoint in JSON format.
Both functions use the https module from Node.js to make the HTTP request and return a promise that resolves with the desired data or rejects with an error.
Importing these functions into the main github action logic we get:
import * as core from '@actions/core'
import {getIpAddress, getIpInfo} from './ip'
import {wait} from './wait'
async function run(): Promise<void> {
try {
const ms: string = core.getInput('milliseconds')
core.debug(`Waiting ${ms} milliseconds ...`) // debug is only output if you set the secret `ACTIONS_STEP_DEBUG` to true
core.debug(new Date().toTimeString())
await wait(parseInt(ms, 10))
core.debug(new Date().toTimeString())
// getIpAddress
// get ip
const ipAddressOfRunner = await getIpAddress()
core.debug(`ipAddressOfRunner: ${ipAddressOfRunner}`)
// get ip info
const ipInfo = await getIpInfo(ipAddressOfRunner)
// output ip info
core.notice(`ipInfo: ${JSON.stringify(ipInfo)}`)
core.setOutput('ip_raw', ipInfo)
// for each property in ipInfo, set output
for (const [key, value] of Object.entries(ipInfo)) {
core.setOutput(key, value)
}
core.notice(`ip: ${ipInfo.ip}`)
core.notice(`country: ${ipInfo.countryname}`)
} catch (error) {
if (error instanceof Error) core.setFailed(error.message)
}
}
run()
It imports the core object from the @actions/core package, as well as the getIpAddress and getIpInfo functions from another module and the wait function from another.
The code defines an async function called run that does the following:
steps:
- uses: actions/checkout@v2
- uses: FriendlyUser/ip_address_of_runner@v1.0.0
id: ip-step
with:
milliseconds: 1000
# script output contents of ip from the step
- run: |
echo "ip: ${{ steps.ip-step.outputs.ip_raw }}"
echo "ip: ${{ steps.ip-step.outputs.ip }}"
echo "ip: ${{ steps.ip-step.outputs.countryname }}"
This is a GitHub Actions workflow. It looks like this workflow is checking out the code repository and running a step called “ip_address_of_runner” from an action called “FriendlyUser/ip_address_of_runner@v1.0.0”. This step is given an id of “ip-step” and is passed an input called “milliseconds” with a value of “1000”.
After the step has run, the workflow echoes the contents of the “ip_raw”, “ip”, and “countryname” outputs from the “ip-step”. These outputs are likely provided by the “FriendlyUser/ip_address_of_runner@v1.0.0” action.
The output is
ip: 104.45.204.209
ip: United States of America
To view the full github action please visit