ORACLE UTL_SMTP SMTP permanent error: 535 5.7.8 - gmail

I'm trying to send email with Oracle APEX 20.1, hence, I've configured the wallet with gmail certificates as I've done before, but now every time I attempt to send an email, always get the same response from google smtp servers:
SMTP permanent error: 535 5.7.8 https://support.google.com/mail/?p=BadCredentials o40-20020a17090a0a2b00b001c77ebd8fa9sm275647pjo.17 - gsmtp
I've trippled check the account credentials, and the account security setting for untrusted apps is enabled.
Here's my procedure for sending email:
No 2 step verification is enabled.
At this point I'm really confused on what might been going on here.
create or replace PROCEDURE SEND_EMAIL(v_to varchar2, v_subject varchar2, v_mensaje varchar2) IS
c utl_smtp.connection;
l_mailhost VARCHAR2 (64) := 'smtp.gmail.com';
l_from VARCHAR2(64) := 'test#test.com';
l_from_alias VARCHAR2 (64) := 'testa#test.com';
l_to VARCHAR2 (64) := v_to;
l_subject VARCHAR2 (64) := v_subject;
l_conn utl_smtp.connection;
l_reply utl_smtp.reply;
crlf varchar2(2) := UTL_TCP.CRLF;
BEGIN
c := utl_smtp.open_connection(
host => l_mailhost,
port => 587,
wallet_path => 'file:/xxxxx/xxxxx',
wallet_password => 'xxxxxxxx',
secure_connection_before_smtp => false);
dbms_output.put_line('utl_smtp.open_connection');
--UTL_SMTP.EHLO(c, 'panamaensalarios.com');
UTL_SMTP.EHLO(c, 'smtp.gmail.com');
UTL_SMTP.starttls(c);
dbms_output.put_line('Usuario : '|| utl_raw.cast_to_varchar2( utl_encode.base64_encode( utl_raw.cast_to_raw(l_from))));
utl_smtp.command( c, 'AUTH LOGIN');
utl_smtp.command( c, utl_raw.cast_to_varchar2( utl_encode.base64_encode( utl_raw.cast_to_raw(l_from))));
utl_smtp.command( c, utl_raw.cast_to_varchar2( utl_encode.base64_encode( utl_raw.cast_to_raw([some_password]))));
UTL_SMTP.mail (c, l_from);
UTL_SMTP.rcpt (c, l_to);
UTL_SMTP.open_data (c);
UTL_SMTP.write_data (c, 'Date: ' || TO_CHAR (SYSDATE, 'DD-MON-YYYY HH24:MI:SS') || crlf);
--UTL_SMTP.write_data (c, 'From: ' || l_from_alias || crlf);
UTL_SMTP.write_data (c, 'From: ' || l_from || crlf);
UTL_SMTP.write_data (c, 'Subject: ' || l_subject || crlf);
UTL_SMTP.write_data (c, 'To: ' || l_to || crlf);
UTL_SMTP.write_data (c, '' || crlf);
--FOR i IN 1 .. 10
-- LOOP
-- UTL_SMTP.write_data (c, 'This is a test message.' || TO_CHAR (i) || crlf);
-- END LOOP;
UTL_SMTP.write_data(c, v_mensaje || crlf);
UTL_SMTP.close_data (c);
UTL_SMTP.quit (c);
EXCEPTION WHEN OTHERS THEN
--UTL_SMTP.quit (c);
GP_AC_P_REGISTRA_LOG('PL','SEND_EMAIL',SYSDATE,USER,'E','error :'||SQLERRM);
DBMS_OUTPUT.PUT_LINE('ERROR: '||SQLERRM);
dbms_output.put_line( dbms_utility.format_error_backtrace );
END;
Thanks in advance for any help.
Kind regards.

Related

Authorization string is not same when generate with golang and JS

I have problem with Golang to generate the correct the correct Authorization string for API access. I try with JS and the string is okay to use while the string from golang can not be used for authentication. Can you help me check what is the different and correct me?
Here is my golang code:
func generateSalt(dataToSign string) string {
token := hmac.New(sha256.New, []byte("secret"))
token.Write([]byte(dataToSign))
macSum := token.Sum(nil)
return base64.StdEncoding.EncodeToString(macSum)
}
func main() {
date = "Wed, 25 May 2022 09:16:45 GMT"
uri := "groups"
url := fmt.Sprintf("https://api-worldcheck.refinitiv.com/v2/%s", uri)
dataToSign := fmt.Sprintf(`(request-target): get %s%vhost: %s%vdate: %s`, "/v2/groups", "\r\n", "api-worldcheck.refinitiv.com", "\r\n", date)
log.Printf("dateToSign: %s", dataToSign)
hmac := generateSalt(dataToSign)
authorization := fmt.Sprintf(`Signature keyId="%s",algorithm="hmac-sha256",headers="(request-target) host date",signature="%s"`, "api-key", hmac)
log.Printf("authorization: %s", authorization)
}
The result from golang is dZzRZfa0yVZsTWof+qEz5VhsFyV83b6DDKXzG9pp/yk=
The code on JS
function generateAuthHeader(dataToSign){
var hash = CryptoJS.HmacSHA256(dataToSign,environment["api-secret"]);
return hash.toString(CryptoJS.enc.Base64);
}
var date = "Wed, 25 May 2022 09:16:45 GMT";
var dataToSign = "(request-target): get " + environment["gateway-url"] + "groups\n" +
"host: " + environment["gateway-host"] + "\n" +
"date: " + date;
console.log("date", date)
console.log({dataToSign})
var hmac = generateAuthHeader(dataToSign);
var authorisation = "Signature keyId=\"" + environment["api-key"] + "\",algorithm=\"hmac-sha256\",headers=\"(request-target) host date\",signature=\"" + hmac + "\"";
console.log({authorisation})
The result is nx5uyMlq4kOxY1fD5OpoLE6UGI+f5p3OUy+l6G8+oxc=
Both the snippets have different data to sign. The JS has some env vars that are used which might be different. I have taken those values from the Go code.
Go code: Go Playground example
// You can edit this code!
// Click here and start typing.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"log"
)
func generateSalt(dataToSign string) string {
token := hmac.New(sha256.New, []byte("secret"))
token.Write([]byte(dataToSign))
macSum := token.Sum(nil)
return base64.StdEncoding.EncodeToString(macSum)
}
func main() {
date := "Wed, 25 May 2022 09:16:45 GMT"
uri := "groups"
url := fmt.Sprintf("https://api-worldcheck.refinitiv.com/v2/%s", uri)
host := "api-worldcheck.refinitiv.com"
dataToSign := fmt.Sprintf("(request-target): get %s\nhost: %s\ndate: %s", url, host, date)
log.Printf("dateToSign: %s", dataToSign)
hmac := generateSalt(dataToSign)
authorization := fmt.Sprintf(`Signature keyId="%s",algorithm="hmac-sha256",headers="(request-target) host date",signature="%s"`, "api-key", hmac)
log.Printf("authorization: %s", authorization)
}
JS Code:
function generateAuthHeader(dataToSign){
var hash = CryptoJS.HmacSHA256(dataToSign, "secret");
return hash.toString(CryptoJS.enc.Base64);
}
var date = "Wed, 25 May 2022 09:16:45 GMT";
var url = "https://api-worldcheck.refinitiv.com/v2/";
var host = "api-worldcheck.refinitiv.com";
var apiKey = "api-key";
var dataToSign = "(request-target): get " + url + "groups\n" +
"host: " + host + "\n" +
"date: " + date;
console.log("date", date)
console.log("dataToSign", dataToSign)
var hmac = generateAuthHeader(dataToSign);
var authorisation = "Signature keyId=\"" + apiKey + "\",algorithm=\"hmac-sha256\",headers=\"(request-target) host date\",signature=\"" + hmac + "\"";
console.log(authorisation);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
Both have the signature as pZjwRvunAPwUs7tFdbFtY6xOLjbpKUYMpnb

Write Node app .js configuration during installation process in Inno Setup

I found out how to create the wizard pages to collect the information I need. But my app has a config.js file, where I need to change some values depending on the user input. What would be the best way to write that file? Write the whole file with SaveStringToFile or import the file somehow and replace certain string parts?
This is a snippet from the current config:
let cfg = {
hapi: {
port: 3000,
host: '0.0.0.0',
maxUploadBytes: 1000000 * 50 // 50 MB
},
jwt: {
key: 'secretkey',
algorithm: 'HS256',
expiresIn: '1h'
},
authentication: {
encryption: {
saltRounds: 10 // will be used in bcrypt to encrypt passwords
}
},
db_config: {
user: 'username',
password: 'pw',
server: 'DESKTOP-IG',
database: 'TestDB-1'
},
scripts: {
ConnectorInstallPath: "C:\\Program\ Files\\ Connector\\"
}
}
I have to change the values for: user: 'username', password: 'pw', server: 'DESKTOP-IG', database: 'TestDB-1', port: 3000, and ConnectorInstallPath: "C:\\Program\ Files\\ Connector\\".
Replacing using a pattern like server: '*' would be enough. It doesn't need to be smarter.
Thanks a lot.
The following function can change a property in your configuration file:
function SetConfigProperty(FileName, Name: string; Value: string): Boolean;
var
Lines: TArrayOfString;
Count, I, P: Integer;
HasComma: Boolean;
Line: string;
State: Integer;
begin
Result := True;
if not LoadStringsFromFile(FileName, Lines) then
begin
Log(Format('Error reading %s', [FileName]));
Result := False;
end
else
begin
State := 0;
Count := GetArrayLength(Lines);
for I := 0 to Count - 1 do
begin
Line := Lines[I];
P := Pos(':', Line);
if (CompareText(Trim(Copy(Line, 1, P - 1)), Name) = 0) then
begin
Log(Format('Found property %s at line %d', [Name, (I + 1)]));
HasComma := (Copy(Trim(Line), Length(Trim(Line)), 1) = ',');
Line := Copy(Line, 1, P) + ' ' + Value;
if HasComma then Line := Line + ',';
Lines[I] := Line;
Result := SaveStringsToFile(FileName, Lines, False);
if not Result then
begin
Log(Format('Error writing %s', [FileName]));
end
else
begin
Log(Format('Modifications saved to %s', [FileName]));
end;
break;
end;
if I = Count - 1 then
begin
Log(Format('Property %s not found', [Name]));
Result := False;
end;
end;
end;
end;
The Value must contain complete contents after the colon. With string properties, is has to contain even the quotes. For example:
SetConfigProperty(FileName, 'server', '''DESKTOP-IG''');
You can use the function for example in the CurStepChanged event function in ssPostInstall step (when the file is already installed):
procedure CurStepChanged(CurStep: TSetupStep);
var
FileName: string;
ErrorCode: Integer;
begin
if CurStep = ssPostInstall then
begin
FileName := ExpandConstant('{app}\config.js');
SetConfigProperty(FileName, 'username', '''' + UsernameEdit.Text + '''');
SetConfigProperty(FileName, 'Password', '''' + PasswordEdit.Text + '''');
SetConfigProperty(FileName, 'server', '''' + ServerEdit.Text + '''');
SetConfigProperty(FileName, 'port', PortEdit.Text);
{ ... }
end;
end;

Inno Setup Get default browser

I have a software which requires the default browser installed on user computer.
Is there a way that I can get it?
Thanks
An solution that correctly works on modern versions of Windows cannot be based on association with http protocol, as that's no longer reliable. It should rather be based on a solution like the answer by #GregT to How to determine the Windows default browser (at the top of the start menu).
So something like:
function GetBrowserCommand: string;
var
UserChoiceKey: string;
HtmlProgId: string;
begin
UserChoiceKey :=
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice';
if RegQueryStringValue(HKCU, UserChoiceKey, 'ProgId', HtmlProgId) then
begin
Log(Format('ProgID to registered for .html is [%s].', [HtmlProgId]));
if RegQueryStringValue(HKCR, HtmlProgId + '\shell\open\command', '', Result) then
begin
Log(Format('Command for ProgID [%s] is [%s].', [HtmlProgId, Result]));
end;
end;
{ Fallback for old version of Windows }
if Result = '' then
begin
if RegQueryStringValue(HKCR, 'http\shell\open\command', '', Result) then
begin
Log(Format('Command registered for http: [%s].', [Result]));
end;
end;
end;
If you want to extract browser path from the command, use a code like:
function ExtractProgramPath(Command: string): string;
var
P: Integer;
begin
if Copy(Command, 1, 1) = '"' then
begin
Delete(Command, 1, 1);
P := Pos('"', Command);
end
else P := 0;
if P = 0 then
begin
P := Pos(' ', Command);
end;
Result := Copy(Command, 1, P - 1);
end;
(based on Executing UninstallString in Inno Setup)
Take this:
function GetBrowser() : String;
var
RegistryEntry: String;
Browser: String;
Limit: Integer ;
begin
if RegQueryStringValue(HKEY_CLASSES_ROOT, 'http\shell\open\command', '', RegistryEntry) then
begin
Limit := Pos('.exe' ,RegistryEntry)+ Length('.exe');
Browser := Copy(RegistryEntry, 1, Limit );
MsgBox('Your browser: ' + Browser , mbInformation, MB_OK);
end;
end;

Verify permissions to run Inno Setup installer online

I am looking for a code for Inno Setup, that I can use to make my setup verify my permission to install the program. This code must check a text file on a web server.
If the file has the value "False", the setup has to cancel an installation and save the value in a registry file to cancel it always when Internet connection is not available.
If the file has the value "True", the setup will continue to install, and it will delete the registry file value if it exists.
If there is no Internet and the registry value does not exist the setup will continue to install.
Use InitializeSetup event function to trigger your check using HTTP request.
[Code]
const
SubkeyName = 'Software\My Program';
AllowInstallationValue = 'Allow Installation';
function IsInstallationAllowed: Boolean;
var
Url: string;
WinHttpReq: Variant;
S: string;
ResultDWord: Cardinal;
begin
try
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
Url := 'https://www.example.com/can_install.txt';
WinHttpReq.Open('GET', Url, False);
WinHttpReq.Send('');
if WinHttpReq.Status <> 200 then
begin
RaiseException(
'HTTP Error: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
end
else
begin
S := Trim(WinHttpReq.ResponseText);
Log('HTTP Response: ' + S);
Result := (CompareText(S, 'true') = 0);
if RegWriteDWordValue(
HKLM, SubkeyName, AllowInstallationValue, Integer(Result)) then
Log('Cached response to registry')
else
Log('Error caching response to registry');
end;
except
Log('Error: ' + GetExceptionMessage);
if RegQueryDWordValue(HKLM, SubkeyName, AllowInstallationValue, ResultDWord) then
begin
Log('Online check failed, using cached result');
Result := (ResultDWord <> 0);
end
else
begin
Log('Online check failed, no cached result, allowing installation by default');
Result := True;
end;
end;
if Result then Log('Can install')
else Log('Cannot install');
end;
function InitializeSetup(): Boolean;
begin
Result := True;
if not IsInstallationAllowed then
begin
MsgBox('You cannot install this', mbError, MB_OK);
Result := False;
end;
end;

Send email from Oracle 12c with postfix on Oracle Linux 7

I have postfix service on my Oracle Linux and they work well done.
I use function
create or replace procedure Send_Mail(Msg_To varchar2, Msg_Subject varchar2, Msg_Text varchar2) is
c Utl_Smtp.Connection;
Rc integer;
Msg_From varchar2(50) := 'me#me.com'; -- email of my company which hosted on Gmail
Mailhost varchar2(30) := 'smtp.gmail.com';
begin
c := Utl_Smtp.Open_Connection(Mailhost, 587);
Utl_Smtp.Helo(c, Mailhost);
Utl_Smtp.StartTLS(c);
Utl_Smtp.Mail(c, Msg_From);
Utl_Smtp.Rcpt(c, Msg_To);
Utl_Smtp.Data(c,
'From: Oracle Database' || Utl_Tcp.Crlf || 'To: ' || Msg_To || Utl_Tcp.Crlf || 'Subject: ' || Msg_Subject || Utl_Tcp.Crlf ||
Msg_Text);
Utl_Smtp.Quit(c);
exception
when Utl_Smtp.Invalid_Operation then
Dbms_Output.Put_Line(' Invalid Operation in Mail attempt
using UTL_SMTP.');
when Utl_Smtp.Transient_Error then
Dbms_Output.Put_Line(' Temporary e-mail issue - try again');
when Utl_Smtp.Permanent_Error then
Dbms_Output.Put_Line(' Permanent Error Encountered.');
end;
which I found on http://www.dba-oracle.com/t_utl_smtp_utility.htm
when I run function
BEGIN
send_mail(msg_to => 'me#me.com',
msg_subject => 'Test subject',
msg_text => 'Test text');
END;
I get a error:
ORA-29279: SMTP permanent error: 530 5.7.0 Must issue a STARTTLS command first. im3sm2477330wjb.13 - gsmtp /* 132/5 selected symbols */
what I did wrong or what I must do?
The error is mentioned in the documentation, which also tells you how to secure the SMTP connection using SSL/TLS. You need to call utl_smtp.starttls().
...
begin
c := Utl_Smtp.Open_Connection(Mailhost, 587);
Utl_Smtp.Ehlo(c, Mailhost);
Utl_Smtp.StartTLS(c);
Utl_Smtp.Ehlo(c, Mailhost);
Utl_Smtp.Mail(c, Msg_From);
Utl_Smtp.Rcpt(c, Msg_To);
...

Resources