-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Sai Ranjit Tummalapalli <[email protected]>
- Loading branch information
1 parent
9850f16
commit 9000558
Showing
9 changed files
with
1,947 additions
and
491 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
node_modules | ||
.DS_Store | ||
build | ||
build | ||
|
||
*.tgz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ | ||
"name": "@adeya/digilocker", | ||
"version": "0.0.0", | ||
"license": "Apache-2.0", | ||
"main": "build/index", | ||
"source": "src/index", | ||
"homepage": "https://github.com/credebl/adeya-sdk/tree/main/packages/digilocker", | ||
"repository": { | ||
"url": "https://github.com/credebl/adeya-sdk/tree/main/packages/digilocker", | ||
"type": "git", | ||
"directory": "packages/digilocker" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"files": [ | ||
"build" | ||
], | ||
"dependencies": { | ||
"axios": "^1.6.0", | ||
"crypto-js": "^4.2.0", | ||
"xml2js": "^0.6.2", | ||
"uuid": "^9.0.0" | ||
}, | ||
"scripts": { | ||
"check-types": "pnpm compile --noEmit", | ||
"build": "pnpm clean && pnpm compile", | ||
"clean": "rimraf -rf ./build", | ||
"compile": "tsc", | ||
"release": "release-it" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^18.18.8", | ||
"rimraf": "3.0.2", | ||
"typescript": "~5.5.2", | ||
"@types/xml2js": "~0.4.14", | ||
"@types/uuid": "^9.0.2" | ||
}, | ||
"peerDependencies": { | ||
"react-native": "*" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export const DIGILOCKER_TOKEN_URL = 'https://api.digitallocker.gov.in/public/oauth2/1/token' | ||
export const DIGILOCKER_AADHAAR = 'https://api.digitallocker.gov.in/public/oauth2/3/xml/eaadhaar' | ||
export const DIGILOCKER_ISSUE_DOCUMENT = 'https://api.digitallocker.gov.in/public/oauth2/2/files/issued' | ||
export const DIGILOCKER_FETCH_DOCUMENT = 'https://api.digitallocker.gov.in/public/oauth2/1/xml/' | ||
export const DIGILOCKER_FETCH_FILE = 'https://api.digitallocker.gov.in/public/oauth2/1/file/' | ||
export const DIGILOCKER_CLIENT_ID_URL_1 = | ||
'https://api.digitallocker.gov.in/public/oauth2/1/authorize?response_type=code&client_id=' | ||
export const DIGILOCKER_REDIRECT_URL_2 = '&redirect_uri=' | ||
export const DIGILOCKER_CODE_CHALLENGE_URL_3 = '&state=adeya2024&code_challenge=' | ||
export const DIGILOCKER_CODE_CHALLENGE_METHOD_URL_4 = '&code_challenge_method=S256' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import axios from 'axios' | ||
import { createHash } from 'crypto' | ||
|
||
import { | ||
DIGILOCKER_AADHAAR, | ||
DIGILOCKER_CLIENT_ID_URL_1, | ||
DIGILOCKER_CODE_CHALLENGE_METHOD_URL_4, | ||
DIGILOCKER_CODE_CHALLENGE_URL_3, | ||
DIGILOCKER_FETCH_DOCUMENT, | ||
DIGILOCKER_FETCH_FILE, | ||
DIGILOCKER_ISSUE_DOCUMENT, | ||
DIGILOCKER_REDIRECT_URL_2, | ||
DIGILOCKER_TOKEN_URL | ||
} from './constant' | ||
|
||
export type AdeyaDigiLockerModuleOptions = { | ||
client_id?: string | undefined | ||
client_secret?: string | undefined | ||
redirect_url?: string | undefined | ||
authCode?: string | undefined | ||
codeVerifier?: string | undefined | ||
} | ||
|
||
export const base64UrlEncodeWithoutPadding = (input: Buffer): string => { | ||
return input.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') | ||
} | ||
|
||
export const generateCodeChallenge = (codeVerifier: string): string => { | ||
const hash = createHash('sha256').update(codeVerifier).digest() | ||
return base64UrlEncodeWithoutPadding(hash) | ||
} | ||
|
||
export const initiateDigiLockerOAuth = async ({ | ||
client_id = '', | ||
redirect_url = '', | ||
codeVerifier = '' | ||
}: AdeyaDigiLockerModuleOptions) => { | ||
try { | ||
const codeChallenge = generateCodeChallenge(codeVerifier) | ||
const authUrl = `${DIGILOCKER_CLIENT_ID_URL_1}${client_id}${DIGILOCKER_REDIRECT_URL_2}${redirect_url}${DIGILOCKER_CODE_CHALLENGE_URL_3}${codeChallenge}${DIGILOCKER_CODE_CHALLENGE_METHOD_URL_4}` | ||
return authUrl | ||
} catch (error) { | ||
return error instanceof Error ? error : new Error('An unknown error occurred') | ||
} | ||
} | ||
|
||
export const fetchDigiLockerToken = async ({ | ||
authCode = '', | ||
client_id = '', | ||
client_secret = '', | ||
redirect_url = '', | ||
codeVerifier = '' | ||
}: AdeyaDigiLockerModuleOptions) => { | ||
const params = | ||
`grant_type=authorization_code&` + | ||
`code=${encodeURIComponent(authCode)}&` + | ||
`client_id=${encodeURIComponent(client_id)}&` + | ||
`client_secret=${encodeURIComponent(client_secret)}&` + | ||
`redirect_uri=${encodeURIComponent(redirect_url)}&` + | ||
`code_verifier=${encodeURIComponent(codeVerifier)}` | ||
|
||
try { | ||
const response = await axios.post(DIGILOCKER_TOKEN_URL, params, { | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
} | ||
}) | ||
return response.data | ||
} catch (error) { | ||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred' | ||
return { message: `Error fetching DigiLocker token: ${errorMessage}` } | ||
} | ||
} | ||
|
||
export const fetchAadhaarData = async (accessToken: string): Promise<{ message: string }> => { | ||
try { | ||
const response = await axios.get(DIGILOCKER_AADHAAR, { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
} | ||
}) | ||
return response.data | ||
} catch (error) { | ||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred' | ||
return { message: `Error fetching Aadhaar data: ${errorMessage}` } | ||
} | ||
} | ||
|
||
export const fetchIssuedDocuments = async (accessToken: string): Promise<{ message: string }> => { | ||
try { | ||
const response = await axios.get(DIGILOCKER_ISSUE_DOCUMENT, { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
} | ||
}) | ||
return response.data | ||
} catch (error) { | ||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred' | ||
return { message: `Error fetching issued documents: ${errorMessage}` } | ||
} | ||
} | ||
|
||
export const fetchDocumentData = async (uri: string, accessToken: string): Promise<{ message: string }> => { | ||
const documentUrl = `${DIGILOCKER_FETCH_DOCUMENT}${uri}` | ||
|
||
try { | ||
const response = await axios.get(documentUrl, { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
} | ||
}) | ||
return response.data | ||
} catch (error) { | ||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred' | ||
return { message: `Error fetching document data: ${errorMessage}` } | ||
} | ||
} | ||
|
||
export const fetchDocument = async (uri: string, accessToken: string): Promise<{ message: string }> => { | ||
const documentUrl = `${DIGILOCKER_FETCH_FILE}${uri}` | ||
|
||
try { | ||
const response = await axios.get(documentUrl, { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
} | ||
}) | ||
return response.data | ||
} catch (error) { | ||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred' | ||
return { message: `Error fetching document data: ${errorMessage}` } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { parseStringPromise } from 'xml2js' | ||
|
||
interface AadhaarData { | ||
uid: string | ||
dob: string | ||
gender: string | ||
name: string | ||
co: string | ||
country: string | ||
district: string | ||
locality: string | ||
pincode: string | ||
state: string | ||
vtc: string | ||
house: string | ||
street: string | ||
landmark: string | ||
postOffice: string | ||
photo: string | ||
} | ||
|
||
interface PANData { | ||
panNumber: string | ||
name: string | ||
dob: string | ||
gender: string | ||
} | ||
|
||
interface DrivingLicenseData { | ||
licenseNumber: string | ||
issuedAt: string | ||
issueDate: string | ||
expiryDate: string | ||
dob: string | ||
swd: string | ||
swdIndicator: string | ||
gender: string | ||
presentAddressLine1: string | ||
presentAddressLine2: string | ||
presentAddressHouse: string | ||
presentAddressLandmark: string | ||
presentAddressLocality: string | ||
presentAddressVtc: string | ||
presentAddressDistrict: string | ||
presentAddressPin: string | ||
presentAddressState: string | ||
presentAddressCountry: string | ||
permanentAddressLine1: string | ||
permanentAddressLine2: string | ||
permanentAddressHouse: string | ||
permanentAddressLandmark: string | ||
permanentAddressLocality: string | ||
permanentAddressVtc: string | ||
permanentAddressDistrict: string | ||
permanentAddressPin: string | ||
permanentAddressState: string | ||
permanentAddressCountry: string | ||
licenseTypes: string | ||
name: string | ||
photo: string | ||
} | ||
|
||
const getOrDefault = (obj: any, path: string[], defaultValue = ''): string => { | ||
return path.reduce((acc, key) => (acc && acc[key] ? acc[key] : defaultValue), obj) | ||
} | ||
|
||
export const parseAadhaarData = async (xmlString: string): Promise<AadhaarData | { error: string }> => { | ||
try { | ||
const result = await parseStringPromise(xmlString) | ||
const uidData = result.Certificate.CertificateData[0].KycRes[0].UidData[0] | ||
const poi = uidData.Poi[0] | ||
const poa = uidData.Poa[0] | ||
const photo = uidData.Pht[0] || '' | ||
|
||
const aadhaarData: AadhaarData = { | ||
uid: getOrDefault(uidData, ['$', 'uid']), | ||
dob: getOrDefault(poi, ['$', 'dob']), | ||
gender: getOrDefault(poi, ['$', 'gender']), | ||
name: getOrDefault(poi, ['$', 'name']), | ||
co: getOrDefault(poa, ['$', 'co']), | ||
country: getOrDefault(poa, ['$', 'country']), | ||
district: getOrDefault(poa, ['$', 'dist']), | ||
locality: getOrDefault(poa, ['$', 'loc']), | ||
pincode: getOrDefault(poa, ['$', 'pc']), | ||
state: getOrDefault(poa, ['$', 'state']), | ||
vtc: getOrDefault(poa, ['$', 'vtc']), | ||
house: getOrDefault(poa, ['$', 'house']), | ||
street: getOrDefault(poa, ['$', 'street']), | ||
landmark: getOrDefault(poa, ['$', 'lm']), | ||
postOffice: getOrDefault(poa, ['$', 'po']), | ||
photo | ||
} | ||
return aadhaarData | ||
} catch (error) { | ||
return { error: 'Error parsing Aadhaar XML. Please check the input data.' } | ||
} | ||
} | ||
|
||
export const parsePANData = async (xmlString: string): Promise<PANData | { error: string }> => { | ||
try { | ||
const result = await parseStringPromise(xmlString) | ||
|
||
const certificate = result?.Certificate | ||
const issuedTo = certificate?.IssuedTo?.[0]?.Person?.[0] | ||
|
||
const panData: PANData = { | ||
panNumber: certificate?.$?.number || '', | ||
name: issuedTo?.$?.name || '', | ||
dob: issuedTo?.$?.dob || '', | ||
gender: issuedTo?.$?.gender || '' | ||
} | ||
|
||
return panData | ||
} catch (error) { | ||
return { error: 'Error parsing PAN XML. Please check the input data.' } | ||
} | ||
} | ||
|
||
export const parseDrivingLicenseData = async (xmlString: string): Promise<DrivingLicenseData | { error: string }> => { | ||
try { | ||
const result = await parseStringPromise(xmlString) | ||
|
||
const certificate = result?.Certificate | ||
const issuedTo = certificate?.IssuedTo?.[0]?.Person?.[0] | ||
const presentAddress = issuedTo?.Address?.[0]?.$ || {} | ||
const permanentAddress = issuedTo?.Address2?.[0]?.$ || {} | ||
const licenseTypes = certificate?.CertificateData[0]?.DrivingLicense[0]?.Categories[0]?.Category | ||
|
||
const drivingLicenseData: DrivingLicenseData = { | ||
licenseNumber: certificate?.$?.number || '', | ||
issuedAt: certificate?.$?.issuedAt || '', | ||
issueDate: certificate?.$?.issueDate || '', | ||
expiryDate: certificate?.$?.expiryDate || '', | ||
dob: issuedTo?.$?.dob || '', | ||
swd: issuedTo?.$?.swd || '', | ||
swdIndicator: issuedTo?.$?.swdIndicator || '', | ||
name: issuedTo?.$?.name || '', | ||
presentAddressLine1: presentAddress.line1 || '', | ||
presentAddressLine2: presentAddress.line2 || '', | ||
presentAddressHouse: presentAddress.house || '', | ||
presentAddressLandmark: presentAddress.landmark || '', | ||
presentAddressLocality: presentAddress.locality || '', | ||
presentAddressVtc: presentAddress.vtc || '', | ||
presentAddressDistrict: presentAddress.district || '', | ||
presentAddressPin: presentAddress.pin || '', | ||
presentAddressState: presentAddress.state || '', | ||
presentAddressCountry: presentAddress.country || '', | ||
permanentAddressLine1: permanentAddress.line1 || '', | ||
permanentAddressLine2: permanentAddress.line2 || '', | ||
permanentAddressHouse: permanentAddress.house || '', | ||
permanentAddressLandmark: permanentAddress.landmark || '', | ||
permanentAddressLocality: permanentAddress.locality || '', | ||
permanentAddressVtc: permanentAddress.vtc || '', | ||
permanentAddressDistrict: permanentAddress.district || '', | ||
permanentAddressPin: permanentAddress.pin || '', | ||
permanentAddressState: permanentAddress.state || '', | ||
permanentAddressCountry: permanentAddress.country || '', | ||
licenseTypes: licenseTypes.map((item: { $: { abbreviation: string } }) => item.$.abbreviation).join(', '), | ||
gender: issuedTo?.$?.gender || '', | ||
photo: issuedTo?.Photo?.[0]._ || '' | ||
} | ||
return drivingLicenseData | ||
} catch (error) { | ||
return { error: 'Error parsing Driving License XML. Please check the input data.' } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './digilocker' | ||
export * from './digilockerDataParse' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "./build" | ||
}, | ||
"include": ["src"] | ||
} |
Oops, something went wrong.