Files
svc-api-x/v1/resources/vault_record.cfc
T
2025-10-24 19:09:22 +03:00

107 lines
4.8 KiB
Plaintext

<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}/vault/{secretName}" hint="getting secrets from the vault">
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent>
<cffunction name="get" hint="Получить секрет">
<cfargument name="instanceUid" type="string" required=true hint="type:UUID"/>
<cfargument name="secretName" type="string" required=true hint="type:string"/>
<!--- <cfargument name="usrId" type="string" hint="type:integer; no need to provide this argument in request, it is injected by IAM"/> --->
<!--- arguments.usrId неявно вбрасывается из Application.cfm --->
<cftry>
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
</cftry>
<cfset var local={}/>
<cfset local.vaultData={}/>
<!--- тут необходимо проконтролировать, что мы смотрим не чужие данные --->
<!--- в других местах мы молча возврашаем пустой резалтсет на запрос чужих данных --->
<!--- варианты: 403, 404, пустой набор данных --->
<cfquery name="local.qCurrentState" result="local.result">
select
<m:field_set titleMapOut="local.currentStateTitleMap" lengthOut="local.fieldCount">
<m:field title="instance_state_uid">st.instance_state_uid::text as instance_state_uid</m:field>
<m:field title="v.">st.version</m:field>
<m:field title="creator_id">st.creator_id</m:field>
<m:field title="dt_state">to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_state</m:field>
<m:field formatter=#request.castToBool#>st.is_test</m:field>
<m:field title="instance_operation_uid">st.instance_operation_uid::text as instance_operation_uid</m:field>
<m:field title="instance_data" formatter=#function(x){return (deserializeJson(x))}#>st.instance_data::text as instance_data</m:field>
<m:field formatter=#function(x){return (x GT 0)}#>(st.instance_data->>'isDeleted')::boolean as is_deleted</m:field>
</m:field_set>
from instance_state st
join instance e on (st.instance_uid=e.instance_uid)
join specification_item i on (e.specification_item_id=i.specification_item_id)
where st.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#"/>
AND i.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- access protection --->
order by st.version desc
limit 1
</cfquery>
<cftry>
<cfset vaultUrl=""/>
<cfset instanceData="#deserializeJson(local.qCurrentState.instance_data)#"/>
<cfif structKeyExists(instanceData,"vaultUrl")>
<cfset vaultUrl=instanceData.vaultUrl/> <!--- v001 --->
<cfelseif structKeyExists(instanceData,"vault")>
<cfset vaultUrl=instanceData.vault.Url/><!--- v002 --->
</cfif>
<!--- *** вынести URL в конфиг --->
<cfhttp method="post"
url="#request.vault_login_url#"
timeout="3"
charset="utf-8"
result="res"
>
<cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/>
<cfhttpparam type="BODY" value='{"role_id":"#request.vault_role_id#","secret_id":"#request.vault_secret_id#"}'/>
</cfhttp>
<cfset resData=#deserializeJson(res.filecontent)#/>
<cfset client_token=#resData.auth.client_token#/>
<cftry>
<cfhttp method="get"
url="#vaultUrl#"
timeout="3"
charset="utf-8"
result="cred">
<cfhttpparam type="HEADER" name="X-Vault-Token" value="#client_token#">
<cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/>
</cfhttp>
<!--- *** костыль для перехода от формата v001 к v002 --->
<cfif structKeyExists(instanceData,"vault")>
<cfset "local.tempVaultData" = #deserializeJson(cred.filecontent).data.data#/>
<cfset "local.vaultData" = local.tempVaultData[arguments.secretName]/>
<!--- <cfelse>
<cfset "local.vaultData" = #deserializeJson(cred.filecontent).data.data#/> --->
</cfif>
<cfcatch type="ANY">
<cfreturn representationOf(cfcatch).withStatus(500)/>
</cfcatch>
</cftry>
<cfcatch type="ANY">
<cfreturn representationOf(cfcatch).withStatus(500)/>
</cfcatch>
</cftry>
<cfset var out = structNew("linked")/>
<cfset "out.name" = #arguments.secretName#/>
<cfset "out.value" = #local.vaultData#/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) />
</cffunction>
</cfcomponent>